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 17:34:32.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 \
874 + mod_proxy_core_backlog.c mod_proxy_core_rewrites.c
875 +mod_proxy_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
876 +mod_proxy_core_la_LIBADD = $(common_libadd) $(PCRE_LIB)
879 lib_LTLIBRARIES += mod_ssi.la
880 mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c
881 mod_ssi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
883 mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
884 configparser.h mod_ssi_exprparser.h \
885 sys-mmap.h sys-socket.h mod_cml.h mod_cml_funcs.h \
886 - splaytree.h proc_open.h
887 + splaytree.h proc_open.h http_resp.h mod_sql_vhost_core.h \
888 + sys-files.h sys-process.h sys-strings.h http_resp_parser.h \
889 + iosocket.h array-static.h \
890 + mod_proxy_core_address.h mod_proxy_core_backend.h \
891 + mod_proxy_core_backlog.h mod_proxy_core.h \
892 + mod_proxy_core_pool.h mod_proxy_core_rewrites.h
894 DEFS= @DEFS@ -DLIBRARY_DIR="\"$(libdir)\""
899 noinst_HEADERS = $(hdr)
900 -EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c
901 +EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c http_resp_parser.y
902 --- ../lighttpd-1.4.11/src/array-static.h 1970-01-01 03:00:00.000000000 +0300
903 +++ lighttpd-1.4.12/src/array-static.h 2006-07-18 13:03:40.000000000 +0300
905 +#ifndef _ARRAY_STATIC_H_
906 +#define _ARRAY_STATIC_H_
908 +/* define a generic array of <type>
911 +#define ARRAY_STATIC_DEF(name, type, extra) \
919 +/* all append operations need a 'resize' for the +1 */
921 +#define ARRAY_STATIC_PREPARE_APPEND(a) \
922 + if (a->size == 0) { \
924 + a->ptr = malloc(a->size * sizeof(*(a->ptr))); \
925 + } else if (a->size == a->used) { \
927 + a->ptr = realloc(a->ptr, a->size * sizeof(*(a->ptr))); \
930 +#define FOREACH(array, element, func) \
931 +do { size_t _i; for (_i = 0; _i < array->used; _i++) { void *element = array->ptr[_i]; func; } } while(0);
933 +#define STRUCT_INIT(type, var) \
935 + var = calloc(1, sizeof(*var))
938 --- ../lighttpd-1.4.11/src/array.c 2005-11-18 13:58:32.000000000 +0200
939 +++ lighttpd-1.4.12/src/array.c 2006-07-16 00:26:03.000000000 +0300
942 array *array_init(void) {
946 a = calloc(1, sizeof(*a));
950 a->next_power_of_2 = 1;
957 void array_free(array *a) {
962 if (!a->is_weakref) {
963 for (i = 0; i < a->size; i++) {
964 if (a->data[i]) a->data[i]->free(a->data[i]);
969 if (a->data) free(a->data);
970 if (a->sorted) free(a->sorted);
976 void array_reset(array *a) {
981 if (!a->is_weakref) {
982 for (i = 0; i < a->used; i++) {
983 a->data[i]->reset(a->data[i]);
992 static int array_get_index(array *a, const char *key, size_t keylen, int *rndx) {
997 if (key == NULL) return -1;
1000 /* try to find the string */
1001 for (i = pos = a->next_power_of_2 / 2; ; i >>= 1) {
1007 } else if (pos >= (int)a->used) {
1010 cmp = buffer_caseless_compare(key, keylen, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used);
1015 ndx = a->sorted[pos];
1016 @@ -110,46 +110,46 @@
1022 if (rndx) *rndx = pos;
1028 data_unset *array_get_element(array *a, const char *key) {
1032 if (-1 != (ndx = array_get_index(a, key, strlen(key) + 1, NULL))) {
1033 /* found, leave here */
1036 return a->data[ndx];
1044 data_unset *array_get_unused_element(array *a, data_type_t t) {
1045 data_unset *ds = NULL;
1050 if (a->size == 0) return NULL;
1053 if (a->used == a->size) return NULL;
1055 if (a->data[a->used]) {
1056 ds = a->data[a->used];
1059 a->data[a->used] = NULL;
1066 /* replace or insert data, return the old one with the same key */
1067 data_unset *array_replace(array *a, data_unset *du) {
1071 if (-1 == (ndx = array_get_index(a, du->key->ptr, du->key->used, NULL))) {
1072 array_insert_unique(a, du);
1074 @@ -164,13 +164,13 @@
1079 - /* generate unique index if neccesary */
1081 + /* generate unique index if necessary */
1082 if (str->key->used == 0 || str->is_index_key) {
1083 buffer_copy_long(str->key, a->unique_ndx++);
1084 str->is_index_key = 1;
1088 /* try to find the string */
1089 if (-1 != (ndx = array_get_index(a, str->key->ptr, str->key->used, &pos))) {
1090 /* found, leave here */
1091 @@ -181,14 +181,14 @@
1100 if (a->used+1 > INT_MAX) {
1101 /* we can't handle more then INT_MAX entries: see array_get_index() */
1108 a->data = malloc(sizeof(*a->data) * a->size);
1109 @@ -204,27 +204,27 @@
1111 for (j = a->used; j < a->size; j++) a->data[j] = NULL;
1115 ndx = (int) a->used;
1118 a->data[a->used++] = str;
1124 buffer_caseless_compare(str->key->ptr, str->key->used, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used) > 0)) {
1128 - /* move everything on step to the right */
1131 + /* move everything one step to the right */
1133 memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted));
1138 a->sorted[pos] = ndx;
1141 if (a->next_power_of_2 == (size_t)ndx) a->next_power_of_2 <<= 1;
1158 array_print_indent(depth);
1159 fprintf(stderr, ")");
1165 @@ -323,47 +323,47 @@
1177 ds = data_string_init();
1178 buffer_copy_string(ds->key, "abc");
1179 buffer_copy_string(ds->value, "alfrag");
1182 array_insert_unique(a, (data_unset *)ds);
1185 ds = data_string_init();
1186 buffer_copy_string(ds->key, "abc");
1187 buffer_copy_string(ds->value, "hameplman");
1190 array_insert_unique(a, (data_unset *)ds);
1193 ds = data_string_init();
1194 buffer_copy_string(ds->key, "123");
1195 buffer_copy_string(ds->value, "alfrag");
1198 array_insert_unique(a, (data_unset *)ds);
1201 dc = data_count_init();
1202 buffer_copy_string(dc->key, "def");
1205 array_insert_unique(a, (data_unset *)dc);
1208 dc = data_count_init();
1209 buffer_copy_string(dc->key, "def");
1212 array_insert_unique(a, (data_unset *)dc);
1221 fprintf(stderr, "%d\n",
1222 buffer_caseless_compare(CONST_STR_LEN("Content-Type"), CONST_STR_LEN("Content-type")));
1228 --- ../lighttpd-1.4.11/src/array.h 2005-09-23 21:24:18.000000000 +0300
1229 +++ lighttpd-1.4.12/src/array.h 2006-07-16 00:26:03.000000000 +0300
1231 #define DATA_UNSET \
1234 - int is_index_key; /* 1 if key is a array index (autogenerated keys) */ \
1235 + int is_index_key; /* 1 if key is an array index (auto-generated keys) */ \
1236 struct data_unset *(*copy)(const struct data_unset *src); \
1237 void (* free)(struct data_unset *p); \
1238 void (* reset)(struct data_unset *p); \
1255 size_t next_power_of_2;
1256 int is_weakref; /* data is weakref, don't bother the data */
1285 COMP_SERVER_SOCKET, COMP_HTTP_URL, COMP_HTTP_HOST, COMP_HTTP_REFERER, COMP_HTTP_USERAGENT, COMP_HTTP_COOKIE, COMP_HTTP_REMOTEIP
1288 -/* $HTTP["host"] == "incremental.home.kneschke.de" { ... }
1289 +/* $HTTP["host"] == "incremental.home.kneschke.de" { ... }
1290 * for print: comp_key op string
1291 * for compare: comp cond string/regex
1294 typedef struct _data_config data_config;
1295 struct _data_config {
1310 int context_ndx; /* more or less like an id */
1314 /* for chaining only */
1331 @@ -120,13 +120,13 @@
1337 unsigned short port;
1344 int usage; /* fair-balancing needs the no. of connections active on this host */
1345 int last_used_ndx; /* round robin */
1347 --- ../lighttpd-1.4.11/src/base.h 2006-01-11 16:51:04.000000000 +0200
1348 +++ lighttpd-1.4.12/src/base.h 2006-07-18 13:03:40.000000000 +0300
1352 #include <sys/types.h>
1353 -#include <sys/time.h>
1354 #include <sys/stat.h>
1356 #ifdef HAVE_CONFIG_H
1358 #include "sys-socket.h"
1359 #include "splaytree.h"
1362 #if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
1363 # define USE_OPENSSL
1364 -# include <openssl/ssl.h>
1365 +# include <openssl/ssl.h>
1373 -#ifndef O_LARGEFILE
1374 -# define O_LARGEFILE 0
1379 # define SIZE_MAX SIZE_T_MAX
1382 /* solaris and NetBSD 1.3.x again */
1383 #if (!defined(HAVE_STDINT_H)) && (!defined(HAVE_INTTYPES_H)) && (!defined(uint32_t))
1384 -# define uint32_t u_int32_t
1385 +/* # define uint32_t u_int32_t */
1386 +typedef unsigned __int32 uint32_t;
1392 #include "settings.h"
1394 -typedef enum { T_CONFIG_UNSET,
1400 +typedef enum { T_CONFIG_UNSET,
1407 } config_values_type_t;
1409 -typedef enum { T_CONFIG_SCOPE_UNSET,
1410 - T_CONFIG_SCOPE_SERVER,
1411 +typedef enum { T_CONFIG_SCOPE_UNSET,
1412 + T_CONFIG_SCOPE_SERVER,
1413 T_CONFIG_SCOPE_CONNECTION
1414 } config_scope_type_t;
1421 config_values_type_t type;
1422 config_scope_type_t scope;
1424 @@ -118,18 +113,6 @@
1431 - struct sockaddr_in6 ipv6;
1433 - struct sockaddr_in ipv4;
1434 -#ifdef HAVE_SYS_UN_H
1435 - struct sockaddr_un un;
1437 - struct sockaddr plain;
1440 /* fcgi_response_header contains ... */
1441 #define HTTP_STATUS BV(0)
1442 #define HTTP_CONNECTION BV(1)
1443 @@ -142,40 +125,40 @@
1444 /* the request-line */
1452 http_method_t http_method;
1453 http_version_t http_version;
1456 buffer *request_line;
1459 /* strings to the header */
1460 buffer *http_host; /* not alloced */
1461 const char *http_range;
1462 const char *http_content_type;
1463 const char *http_if_modified_since;
1464 const char *http_if_none_match;
1471 size_t content_length; /* returned by strtoul() */
1474 /* internal representation */
1475 int accept_encoding;
1483 off_t content_length;
1484 - int keep_alive; /* used by the subrequests in proxy, cgi and fcgi to say the subrequest was keep-alive or not */
1486 + int keep_alive; /* used by the subrequests in proxy, cgi and fcgi to say whether the subrequest was keep-alive or not */
1493 HTTP_TRANSFER_ENCODING_IDENTITY, HTTP_TRANSFER_ENCODING_CHUNKED
1494 } transfer_encoding;
1496 @@ -191,21 +174,21 @@
1499 buffer *basedir; /* path = "(basedir)(.*)" */
1502 buffer *doc_root; /* path = doc_root + rel_path */
1523 @@ -215,20 +198,20 @@
1527 - splay_tree *files; /* the nodes of the tree are stat_cache_entry's */
1529 + splay_tree *files; /* the nodes of the tree are stat_cache_entries */
1531 buffer *dir_name; /* for building the dirname from the filename */
1533 splay_tree *dirs; /* the nodes of the tree are fam_dir_entry */
1545 /* virtual-servers */
1546 buffer *document_root;
1547 buffer *server_name;
1550 buffer *dirlist_encoding;
1551 buffer *errorfile_prefix;
1554 unsigned short max_keep_alive_requests;
1555 unsigned short max_keep_alive_idle;
1556 unsigned short max_read_idle;
1557 @@ -244,16 +227,17 @@
1558 unsigned short use_xattr;
1559 unsigned short follow_symlink;
1560 unsigned short range_requests;
1566 unsigned short log_file_not_found;
1567 unsigned short log_request_header;
1568 unsigned short log_request_handling;
1569 unsigned short log_response_header;
1570 unsigned short log_condition_handling;
1573 + unsigned short log_condition_cache_handling;
1577 buffer *ssl_pemfile;
1578 buffer *ssl_ca_file;
1579 @@ -268,22 +252,22 @@
1581 unsigned short global_kbytes_per_second; /* */
1583 - off_t global_bytes_per_second_cnt;
1584 + off_t global_bytes_per_second_cnt;
1585 /* server-wide traffic-shaper
1588 * each context has the counter which is inited once
1589 - * a second by the global_kbytes_per_second config-var
1590 + * per second by the global_kbytes_per_second config-var
1592 * as soon as global_kbytes_per_second gets below 0
1593 * the connected conns are "offline" a little bit
1596 - * we somehow have to loose our "we are writable" signal
1597 + * we somehow have to lose our "we are writable" signal
1602 off_t *global_bytes_per_second_cnt_ptr; /* */
1608 @@ -291,18 +275,18 @@
1610 /* the order of the items should be the same as they are processed
1611 * read before write as we use this later */
1613 - CON_STATE_CONNECT,
1614 - CON_STATE_REQUEST_START,
1616 - CON_STATE_REQUEST_END,
1617 - CON_STATE_READ_POST,
1618 - CON_STATE_HANDLE_REQUEST,
1619 - CON_STATE_RESPONSE_START,
1621 - CON_STATE_RESPONSE_END,
1625 + CON_STATE_CONNECT,
1626 + CON_STATE_REQUEST_START,
1628 + CON_STATE_REQUEST_END,
1629 + CON_STATE_READ_POST,
1630 + CON_STATE_HANDLE_REQUEST,
1631 + CON_STATE_RESPONSE_START,
1633 + CON_STATE_RESPONSE_END,
1636 } connection_state_t;
1638 typedef enum { COND_RESULT_UNSET, COND_RESULT_FALSE, COND_RESULT_TRUE } cond_result_t;
1639 @@ -315,91 +299,86 @@
1642 connection_state_t state;
1646 time_t read_idle_ts;
1647 time_t close_timeout_ts;
1648 time_t write_request_ts;
1651 time_t connection_start;
1652 time_t request_start;
1655 struct timeval start_tv;
1658 size_t request_count; /* number of requests handled in this connection */
1659 size_t loops_per_request; /* to catch endless loops in a single request
1662 * used by mod_rewrite, mod_fastcgi, ... and others
1663 * this is self-protection
1666 - int fd; /* the FD for this connection */
1667 - int fde_ndx; /* index for the fdevent-handler */
1670 int ndx; /* reverse mapping to server->connection[ndx] */
1677 - int keep_alive; /* only request.c can enable it, all other just disable */
1680 + int keep_alive; /* only request.c can enable it, all others just disable */
1686 chunkqueue *write_queue; /* a large queue for low-level write ( HTTP response ) [ file, mem ] */
1687 chunkqueue *read_queue; /* a small queue for low-level read ( HTTP request ) [ mem ] */
1688 chunkqueue *request_content_queue; /* takes request-content into tempfile if necessary [ tempfile, mem ]*/
1691 int traffic_limit_reached;
1694 off_t bytes_written; /* used by mod_accesslog, mod_rrd */
1695 off_t bytes_written_cur_second; /* used by mod_accesslog, mod_rrd */
1696 off_t bytes_read; /* used by mod_accesslog, mod_rrd */
1704 buffer *dst_addr_buf;
1707 buffer *parse_request;
1708 unsigned int parsed_response; /* bitfield which contains the important header-fields of the parsed response header */
1713 - physical physical;
1714 + physical physical;
1721 buffer *authed_user;
1722 array *environment; /* used to pass lighttpd internal stuff to the FastCGI/CGI apps, setenv does that */
1732 connection_type mode;
1735 void **plugin_ctx; /* plugin connection specific config */
1738 specific_config conf; /* global connection specific config */
1739 cond_cache_t *cond_cache;
1742 buffer *server_name;
1746 buffer *error_handler;
1747 int error_handler_saved_status;
1748 int in_error_handler;
1751 void *srv_socket; /* reference to the server-socket (typecast to server_socket) */
1759 @@ -439,55 +418,63 @@
1764 + NETWORK_STATUS_UNSET,
1765 + NETWORK_STATUS_SUCCESS,
1766 + NETWORK_STATUS_FATAL_ERROR,
1767 + NETWORK_STATUS_CONNECTION_CLOSE,
1768 + NETWORK_STATUS_WAIT_FOR_EVENT,
1769 + NETWORK_STATUS_INTERRUPTED
1770 +} network_status_t;
1773 unsigned short port;
1776 - buffer *errorlog_file;
1777 - unsigned short errorlog_use_syslog;
1780 unsigned short dont_daemonize;
1789 buffer *event_handler;
1792 buffer *modules_dir;
1793 buffer *network_backend;
1795 array *upload_tempdirs;
1798 unsigned short max_worker;
1799 unsigned short max_fds;
1800 unsigned short max_conns;
1801 unsigned short max_request_size;
1804 unsigned short log_request_header_on_error;
1805 unsigned short log_state_handling;
1807 - enum { STAT_CACHE_ENGINE_UNSET,
1808 - STAT_CACHE_ENGINE_NONE,
1809 - STAT_CACHE_ENGINE_SIMPLE,
1810 - STAT_CACHE_ENGINE_FAM
1812 + enum { STAT_CACHE_ENGINE_UNSET,
1813 + STAT_CACHE_ENGINE_NONE,
1814 + STAT_CACHE_ENGINE_SIMPLE,
1815 + STAT_CACHE_ENGINE_FAM
1816 } stat_cache_engine;
1817 unsigned short enable_cores;
1819 + buffer *errorlog_file;
1820 + unsigned short errorlog_use_syslog;
1830 buffer *ssl_pemfile;
1831 buffer *ssl_ca_file;
1832 unsigned short use_ipv6;
1833 unsigned short is_ssl;
1842 @@ -495,37 +482,32 @@
1845 server_socket **ptr;
1850 } server_socket_array;
1852 typedef struct server {
1853 server_socket_array srv_sockets;
1855 - /* the errorlog */
1857 - enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } errorlog_mode;
1858 - buffer *errorlog_buf;
1861 fdevents *ev, *ev_ins;
1864 buffer_plugin plugins;
1878 int max_fds; /* max possible fds */
1879 int cur_fds; /* currently used fds */
1880 int want_fds; /* waiting fds */
1881 int sockets_disabled;
1887 @@ -533,13 +515,13 @@
1888 buffer *response_header;
1889 buffer *response_range;
1893 buffer *tmp_chunk_len;
1896 buffer *empty_string; /* is necessary for cond_match */
1898 buffer *cond_check_buf;
1903 inet_ntop_cache_type inet_ntop_cache[INET_NTOP_CACHE_MAX];
1904 @@ -547,31 +529,31 @@
1905 mtime_cache_type mtime_cache[FILE_CACHE_MAX];
1912 time_t last_generated_date_ts;
1913 time_t last_generated_debug_ts;
1917 buffer *ts_debug_str;
1918 buffer *ts_date_str;
1923 array *config_touched;
1926 array *config_context;
1927 specific_config **config_storage;
1930 server_config srvconf;
1933 int config_deprecated;
1937 connections *joblist;
1938 connections *fdwaitqueue;
1941 stat_cache *stat_cache;
1944 @@ -588,18 +570,20 @@
1945 * fastcgi.backend.<key>.disconnects = ...
1950 fdevent_handler_t event_handler;
1952 - int (* network_backend_write)(struct server *srv, connection *con, int fd, chunkqueue *cq);
1953 - int (* network_backend_read)(struct server *srv, connection *con, int fd, chunkqueue *cq);
1954 + network_status_t (* network_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1955 + network_status_t (* network_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1957 - int (* network_ssl_backend_write)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
1958 - int (* network_ssl_backend_read)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
1959 + network_status_t (* network_ssl_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1960 + network_status_t (* network_ssl_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1970 --- ../lighttpd-1.4.11/src/bitset.c 2005-08-22 01:54:12.000000000 +0300
1971 +++ lighttpd-1.4.12/src/bitset.c 2006-07-18 13:03:40.000000000 +0300
1978 #define BITSET_BITS \
1979 ( CHAR_BIT * sizeof(size_t) )
1980 --- ../lighttpd-1.4.11/src/buffer.c 2006-01-13 00:00:45.000000000 +0200
1981 +++ lighttpd-1.4.12/src/buffer.c 2006-07-18 13:03:40.000000000 +0300
1992 buffer* buffer_init(void) {
1996 b = malloc(sizeof(*b));
2018 void buffer_free(buffer *b) {
2021 void buffer_reset(buffer *b) {
2025 /* limit don't reuse buffer larger than ... bytes */
2026 if (b->size > BUFFER_MAX_REUSE_SIZE) {
2039 - * allocate (if neccessary) enough space for 'size' bytes and
2041 + * allocate (if necessary) enough space for 'size' bytes and
2042 * set the 'used' counter to 0
2047 #define BUFFER_PIECE_SIZE 64
2049 int buffer_prepare_copy(buffer *b, size_t size) {
2052 - if ((0 == b->size) ||
2054 + if ((0 == b->size) ||
2056 if (b->size) free(b->ptr);
2061 - /* always allocate a multiply of BUFFER_PIECE_SIZE */
2063 + /* always allocate a multiple of BUFFER_PIECE_SIZE */
2064 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2067 b->ptr = malloc(b->size);
2075 - * increase the internal buffer (if neccessary) to append another 'size' byte
2077 + * increase the internal buffer (if necessary) to append another 'size' byte
2078 * ->used isn't changed
2083 int buffer_prepare_append(buffer *b, size_t size) {
2090 - /* always allocate a multiply of BUFFER_PIECE_SIZE */
2092 + /* always allocate a multiple of BUFFER_PIECE_SIZE */
2093 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2096 b->ptr = malloc(b->size);
2099 } else if (b->used + size > b->size) {
2102 - /* always allocate a multiply of BUFFER_PIECE_SIZE */
2104 + /* always allocate a multiple of BUFFER_PIECE_SIZE */
2105 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2108 b->ptr = realloc(b->ptr, b->size);
2113 int buffer_copy_string(buffer *b, const char *s) {
2117 if (!s || !b) return -1;
2119 s_len = strlen(s) + 1;
2120 @@ -136,26 +136,26 @@
2122 int buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
2123 if (!s || !b) return -1;
2125 - /* removed optimization as we have to keep the empty string
2127 + /* removed optimization as we have to keep the empty string
2128 * in some cases for the config handling
2131 * url.access-deny = ( "" )
2133 if (s_len == 0) return 0;
2136 buffer_prepare_copy(b, s_len + 1);
2139 memcpy(b->ptr, s, s_len);
2140 b->ptr[s_len] = '\0';
2141 b->used = s_len + 1;
2147 int buffer_copy_string_buffer(buffer *b, const buffer *src) {
2148 if (!src) return -1;
2151 if (src->used == 0) {
2154 @@ -201,10 +201,10 @@
2157 * append a string to the end of the buffer
2159 - * the resulting buffer is terminated with a '\0'
2160 - * s is treated as a un-terminated string (a \0 is handled a normal character)
2163 + * the resulting buffer is terminated with a '\0'
2164 + * s is treated as an un-terminated string (a \0 is handled as a normal character)
2167 * @param s the string
2168 * @param s_len size of the string (without the terminating \0)
2170 int buffer_append_string_buffer(buffer *b, const buffer *src) {
2171 if (!src) return -1;
2172 if (src->used == 0) return 0;
2175 return buffer_append_string_len(b, src->ptr, src->used - 1);
2180 int buffer_copy_memory(buffer *b, const char *s, size_t s_len) {
2181 if (!s || !b) return -1;
2187 return buffer_append_memory(b, s, s_len);
2190 @@ -402,46 +402,115 @@
2196 + * init the ptr buffer
2199 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer)
2201 + buffer_ptr *l = calloc(1, sizeof(buffer_ptr));
2208 + * free the buffer_array
2211 +void buffer_ptr_free(buffer_ptr *l)
2214 + buffer_ptr_clear(l);
2219 +void buffer_ptr_clear(buffer_ptr *l)
2221 + assert(NULL != l);
2223 + if (l->free && l->used) {
2225 + for (i = 0; i < l->used; i ++) {
2226 + l->free(l->ptr[i]);
2238 +void buffer_ptr_append(buffer_ptr* l, void *item)
2240 + assert(NULL != l);
2241 + if (l->ptr == NULL) {
2243 + l->ptr = (void **)malloc(sizeof(void *) * l->size);
2245 + else if (l->used == l->size) {
2247 + l->ptr = realloc(l->ptr, sizeof(void *) * l->size);
2249 + l->ptr[l->used++] = item;
2252 +void *buffer_ptr_pop(buffer_ptr* l)
2254 + assert(NULL != l && l->used > 0);
2255 + return l->ptr[--l->used];
2258 +void *buffer_ptr_top(buffer_ptr* l)
2260 + assert(NULL != l && l->used > 0);
2261 + return l->ptr[l->used-1];
2269 buffer_array* buffer_array_init(void) {
2273 b = malloc(sizeof(*b));
2285 void buffer_array_reset(buffer_array *b) {
2292 /* if they are too large, reduce them */
2293 for (i = 0; i < b->used; i++) {
2294 buffer_reset(b->ptr[i]);
2303 - * free the buffer_array
2305 + * free the buffer_array
2309 void buffer_array_free(buffer_array *b) {
2314 for (i = 0; i < b->size; i++) {
2315 if (b->ptr[i]) buffer_free(b->ptr[i]);
2319 buffer *buffer_array_append_get_buffer(buffer_array *b) {
2325 b->ptr = malloc(sizeof(*b->ptr) * b->size);
2326 @@ -467,13 +536,13 @@
2332 if (b->ptr[b->used] == NULL) {
2333 b->ptr[b->used] = buffer_init();
2337 b->ptr[b->used]->used = 0;
2340 return b->ptr[b->used++];
2343 @@ -482,23 +551,23 @@
2345 if (len == 0) return NULL;
2346 if (needle == NULL) return NULL;
2349 if (b->used < len) return NULL;
2352 for(i = 0; i < b->used - len; i++) {
2353 if (0 == memcmp(b->ptr + i, needle, len)) {
2362 buffer *buffer_init_string(const char *str) {
2363 buffer *b = buffer_init();
2366 buffer_copy_string(b, str);
2376 - * check if two buffer contain the same data
2378 + * check if two buffers contain the same data
2380 * HISTORY: this function was pretty much optimized, but didn't handled
2381 * alignment properly.
2383 @@ -517,105 +586,105 @@
2384 if (a->used != b->used) return 0;
2385 if (a->used == 0) return 1;
2387 - return (0 == strcmp(a->ptr, b->ptr));
2388 + return (0 == strncmp(a->ptr, b->ptr, a->used - 1));
2391 int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {
2399 return buffer_is_equal(a, &b);
2402 /* simple-assumption:
2404 - * most parts are equal and doing a case conversion needs time
2407 + * most parts are equal and doing a case conversion takes time
2410 int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len) {
2411 size_t ndx = 0, max_ndx;
2413 size_t mask = sizeof(*al) - 1;
2419 - /* is the alignment correct ? */
2421 + /* is the alignment correct? */
2422 if ( ((size_t)al & mask) == 0 &&
2423 ((size_t)bl & mask) == 0 ) {
2426 max_ndx = ((a_len < b_len) ? a_len : b_len) & ~mask;
2429 for (; ndx < max_ndx; ndx += sizeof(*al)) {
2430 if (*al != *bl) break;
2444 max_ndx = ((a_len < b_len) ? a_len : b_len);
2447 for (; ndx < max_ndx; ndx++) {
2448 char a1 = *a++, b1 = *b++;
2452 if ((a1 >= 'A' && a1 <= 'Z') && (b1 >= 'a' && b1 <= 'z'))
2454 else if ((a1 >= 'a' && a1 <= 'z') && (b1 >= 'A' && b1 <= 'Z'))
2456 if ((a1 - b1) != 0) return (a1 - b1);
2468 * check if the rightmost bytes of the string are equal.
2475 int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
2476 /* no, len -> equal */
2477 if (len == 0) return 1;
2480 /* len > 0, but empty buffers -> not equal */
2481 if (b1->used == 0 || b2->used == 0) return 0;
2484 /* buffers too small -> not equal */
2485 - if (b1->used - 1 < len || b1->used - 1 < len) return 0;
2487 - if (0 == strncmp(b1->ptr + b1->used - 1 - len,
2488 + if (b1->used - 1 < len || b2->used - 1 < len) return 0;
2490 + if (0 == strncmp(b1->ptr + b1->used - 1 - len,
2491 b2->ptr + b2->used - 1 - len, len)) {
2499 int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
2504 if (in_len * 2 < in_len) return -1;
2507 buffer_prepare_copy(b, in_len * 2 + 1);
2510 for (i = 0; i < in_len; i++) {
2511 b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F];
2512 b->ptr[b->used++] = hex_chars[in[i] & 0x0F];
2514 b->ptr[b->used++] = '\0';
2521 0 1 2 3 4 5 6 7 8 9 A B C D E F
2523 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2524 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2525 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2526 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, /* 20 - 2F space " # $ % & ' + , / */
2527 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 30 - 3F : ; = ? @ < > */
2528 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
2530 0 1 2 3 4 5 6 7 8 9 A B C D E F
2532 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2533 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2534 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2535 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, /* 20 - 2F space " # $ % & ' + , / */
2536 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 30 - 3F : ; = ? @ < > */
2537 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
2539 0 1 2 3 4 5 6 7 8 9 A B C D E F
2541 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2542 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2543 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2544 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F & */
2545 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 30 - 3F < > */
2546 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
2548 0 1 2 3 4 5 6 7 8 9 A B C D E F
2550 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2551 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2552 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2553 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F & */
2554 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 30 - 3F < > */
2555 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
2556 @@ -712,12 +781,12 @@
2557 0 1 2 3 4 5 6 7 8 9 A B C D E F
2559 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2560 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2561 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
2562 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
2563 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
2564 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
2565 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
2566 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2567 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
2568 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
2569 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
2570 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
2571 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
2572 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 70 - 7F */
2573 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 - 8F */
2574 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 - 9F */
2575 @@ -734,13 +803,12 @@
2576 unsigned char *ds, *d;
2578 const char *map = NULL;
2581 if (!s || !b) return -1;
2583 - if (b->ptr[b->used - 1] != '\0') {
2587 + if (b->used == 0) return -1;
2589 + if (b->ptr[b->used - 1] != '\0') return -1;
2591 if (s_len == 0) return 0;
2594 @@ -760,12 +828,12 @@
2595 map = encoded_chars_hex;
2597 case ENCODING_UNSET:
2599 + return buffer_append_string_len(b, s, s_len);
2602 assert(map != NULL);
2604 - /* count to-be-encoded-characters */
2606 + /* count to-be-encoded characters */
2607 for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2616 buffer_prepare_append(b, d_len);
2619 for (ds = (unsigned char *)s, d = (unsigned char *)b->ptr + b->used - 1, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2622 @@ -820,16 +888,16 @@
2626 - /* terminate buffer and calculate new length */
2627 + /* terminate buffer and calculate new length */
2628 b->ptr[b->used + d_len - 1] = '\0';
2637 -/* decodes url-special-chars inplace.
2638 +/* decodes url-special chars in-place.
2639 * replaces non-printable characters with '_'
2642 @@ -854,10 +922,10 @@
2643 low = hex2int(*(src + 2));
2645 high = (high << 4) | low;
2647 - /* map control-characters out */
2649 + /* map out control characters */
2650 if (high < 32 || high == 127) high = '_';
2657 * /abc/./xyz gets /abc/xyz
2658 * /abc//xyz gets /abc/xyz
2660 - * NOTE: src and dest can point to the same buffer, in which case,
2661 + * NOTE: src and dest can point to the same buffer, in which case
2662 * the operation is performed in-place.
2665 @@ -979,7 +1047,7 @@
2667 int light_isxdigit(int c) {
2668 if (light_isdigit(c)) return 1;
2672 return (c >= 'a' && c <= 'f');
2674 @@ -993,31 +1061,56 @@
2675 return light_isdigit(c) || light_isalpha(c);
2678 +#undef BUFFER_CTYPE_FUNC
2679 +#define BUFFER_CTYPE_FUNC(type) \
2680 + int buffer_is##type(buffer *b) { \
2682 + if (b->used < 2) return 0; \
2684 + len = b->used - 1; \
2685 + /* c-string only */ \
2686 + if (b->ptr[len] != '\0') { \
2689 + /* check on the whole string */ \
2690 + for (i = 0; i < len; i ++) { \
2691 + if (!light_is##type(b->ptr[i])) { \
2698 +BUFFER_CTYPE_FUNC(digit)
2699 +BUFFER_CTYPE_FUNC(xdigit)
2700 +BUFFER_CTYPE_FUNC(alpha)
2701 +BUFFER_CTYPE_FUNC(alnum)
2703 int buffer_to_lower(buffer *b) {
2707 if (b->used == 0) return 0;
2710 for (c = b->ptr; *c; c++) {
2711 if (*c >= 'A' && *c <= 'Z') {
2721 int buffer_to_upper(buffer *b) {
2725 if (b->used == 0) return 0;
2728 for (c = b->ptr; *c; c++) {
2729 if (*c >= 'a' && *c <= 'z') {
2737 --- ../lighttpd-1.4.11/src/buffer.h 2006-01-13 00:00:45.000000000 +0200
2738 +++ lighttpd-1.4.12/src/buffer.h 2006-07-18 13:03:40.000000000 +0300
2749 +typedef void (*buffer_ptr_free_t)(void *p);
2755 + buffer_ptr_free_t free;
2769 - size_t offset; /* input-pointer */
2771 - size_t used; /* output-pointer */
2773 + size_t offset; /* input pointer */
2775 + size_t used; /* output pointer */
2779 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer);
2780 +void buffer_ptr_free(buffer_ptr *b);
2781 +void buffer_ptr_clear(buffer_ptr *b);
2782 +void buffer_ptr_append(buffer_ptr *b, void *item);
2783 +void *buffer_ptr_pop(buffer_ptr *b);
2784 +void *buffer_ptr_top(buffer_ptr *b);
2786 buffer_array* buffer_array_init(void);
2787 void buffer_array_free(buffer_array *b);
2788 void buffer_array_reset(buffer_array *b);
2790 buffer* buffer_init_string(const char *str);
2791 void buffer_free(buffer *b);
2792 void buffer_reset(buffer *b);
2795 int buffer_prepare_copy(buffer *b, size_t size);
2796 int buffer_prepare_append(buffer *b, size_t size);
2802 - ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of a href */
2803 - ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus coding / too as %2F */
2804 - ENCODING_HTML, /* & becomes & and so on */
2805 + ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of an href */
2806 + ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus encoding "/" as "%2F" */
2807 + ENCODING_HTML, /* "&" becomes "&" and so on */
2808 ENCODING_MINIMAL_XML, /* minimal encoding for xml */
2809 ENCODING_HEX /* encode string as hex */
2810 } buffer_encoding_t;
2811 @@ -111,20 +127,23 @@
2812 int light_isalpha(int c);
2813 int light_isalnum(int c);
2815 +#define BUFFER_CTYPE_FUNC(type) int buffer_is##type(buffer *b);
2816 +BUFFER_CTYPE_FUNC(digit)
2817 +BUFFER_CTYPE_FUNC(xdigit)
2818 +BUFFER_CTYPE_FUNC(alpha)
2819 +BUFFER_CTYPE_FUNC(alnum)
2821 +#define BUF_STR(x) x->ptr
2822 #define BUFFER_APPEND_STRING_CONST(x, y) \
2823 buffer_append_string_len(x, y, sizeof(y) - 1)
2825 #define BUFFER_COPY_STRING_CONST(x, y) \
2826 buffer_copy_string_len(x, y, sizeof(y) - 1)
2828 -#define BUFFER_APPEND_SLASH(x) \
2829 - if (x->used > 1 && x->ptr[x->used - 2] != '/') { BUFFER_APPEND_STRING_CONST(x, "/"); }
2831 #define CONST_STR_LEN(x) x, x ? sizeof(x) - 1 : 0
2832 -#define CONST_BUF_LEN(x) x->ptr, x->used ? x->used - 1 : 0
2833 +#define CONST_BUF_LEN(x) BUF_STR(x), x->used ? x->used - 1 : 0
2836 -#define SEGFAULT() do { fprintf(stderr, "%s.%d: aborted\n", __FILE__, __LINE__); abort(); } while(0)
2838 #define UNUSED(x) ( (void)(x) )
2841 --- ../lighttpd-1.4.11/src/chunk.c 2005-11-18 15:18:19.000000000 +0200
2842 +++ lighttpd-1.4.12/src/chunk.c 2006-07-18 13:03:40.000000000 +0300
2845 * the network chunk-API
2852 #include <sys/types.h>
2853 #include <sys/stat.h>
2854 -#include <sys/mman.h>
2858 -#include <unistd.h>
2866 +#include "sys-mmap.h"
2867 +#include "sys-files.h"
2869 chunkqueue *chunkqueue_init(void) {
2873 cq = calloc(1, sizeof(*cq));
2886 static chunk *chunk_init(void) {
2890 c = calloc(1, sizeof(*c));
2893 c->mem = buffer_init();
2894 c->file.name = buffer_init();
2896 c->file.mmap.start = MAP_FAILED;
2903 static void chunk_free(chunk *c) {
2907 buffer_free(c->mem);
2908 buffer_free(c->file.name);
2912 static void chunk_reset(chunk *c) {
2916 buffer_reset(c->mem);
2918 if (c->file.is_temp && !buffer_is_empty(c->file.name)) {
2919 unlink(c->file.name->ptr);
2923 buffer_reset(c->file.name);
2925 if (c->file.fd != -1) {
2928 void chunkqueue_free(chunkqueue *cq) {
2935 for (c = cq->first; c; ) {
2942 for (c = cq->unused; c; ) {
2952 static chunk *chunkqueue_get_unused_chunk(chunkqueue *cq) {
2955 - /* check if we have a unused chunk */
2957 + /* check if we have an unused chunk */
2961 @@ -109,18 +110,18 @@
2963 cq->unused_chunks--;
2970 static int chunkqueue_prepend_chunk(chunkqueue *cq, chunk *c) {
2971 c->next = cq->first;
2975 if (cq->last == NULL) {
2983 @@ -129,19 +130,19 @@
2989 if (cq->first == NULL) {
2997 void chunkqueue_reset(chunkqueue *cq) {
2999 /* move everything to the unused queue */
3001 - /* mark all read written */
3003 + /* mark all read written */
3004 for (c = cq->first; c; c = c->next) {
3009 c->offset = c->file.length;
3016 @@ -162,93 +163,93 @@
3018 int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
3022 if (len == 0) return 0;
3025 c = chunkqueue_get_unused_chunk(cq);
3028 c->type = FILE_CHUNK;
3031 buffer_copy_string_buffer(c->file.name, fn);
3032 c->file.start = offset;
3033 c->file.length = len;
3037 chunkqueue_append_chunk(cq, c);
3043 int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
3047 if (mem->used == 0) return 0;
3050 c = chunkqueue_get_unused_chunk(cq);
3051 c->type = MEM_CHUNK;
3053 buffer_copy_string_buffer(c->mem, mem);
3056 chunkqueue_append_chunk(cq, c);
3062 int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
3066 if (mem->used == 0) return 0;
3069 c = chunkqueue_get_unused_chunk(cq);
3070 c->type = MEM_CHUNK;
3072 buffer_copy_string_buffer(c->mem, mem);
3075 chunkqueue_prepend_chunk(cq, c);
3081 int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
3085 if (len == 0) return 0;
3088 c = chunkqueue_get_unused_chunk(cq);
3089 c->type = MEM_CHUNK;
3091 buffer_copy_string_len(c->mem, mem, len - 1);
3094 chunkqueue_append_chunk(cq, c);
3100 buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
3104 c = chunkqueue_get_unused_chunk(cq);
3107 c->type = MEM_CHUNK;
3109 buffer_reset(c->mem);
3112 chunkqueue_prepend_chunk(cq, c);
3118 buffer *chunkqueue_get_append_buffer(chunkqueue *cq) {
3122 c = chunkqueue_get_unused_chunk(cq);
3125 c->type = MEM_CHUNK;
3127 buffer_reset(c->mem);
3130 chunkqueue_append_chunk(cq, c);
3137 chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
3139 buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX");
3142 c = chunkqueue_get_unused_chunk(cq);
3144 c->type = FILE_CHUNK;
3145 @@ -273,12 +274,12 @@
3148 /* we have several tempdirs, only if all of them fail we jump out */
3151 for (i = 0; i < cq->tempdirs->used; i++) {
3152 data_string *ds = (data_string *)cq->tempdirs->data[i];
3154 buffer_copy_string_buffer(template, ds->value);
3155 - BUFFER_APPEND_SLASH(template);
3156 + PATHNAME_APPEND_SLASH(template);
3157 BUFFER_APPEND_STRING_CONST(template, "lighttpd-upload-XXXXXX");
3159 if (-1 != (c->file.fd = mkstemp(template->ptr))) {
3161 chunkqueue_append_chunk(cq, c);
3163 buffer_free(template);
3170 off_t chunkqueue_length(chunkqueue *cq) {
3175 for (c = cq->first; c; c = c->next) {
3178 @@ -321,14 +322,14 @@
3187 off_t chunkqueue_written(chunkqueue *cq) {
3192 for (c = cq->first; c; c = c->next) {
3204 @@ -355,12 +356,13 @@
3208 + if (c->mem->used == 0) is_finished = 1;
3209 if (c->offset == (off_t)c->mem->used - 1) is_finished = 1;
3212 - if (c->offset == c->file.length) is_finished = 1;
3213 + if (c->offset == c->file.length) is_finished = 1;
3220 @@ -383,3 +385,50 @@
3225 +void chunkqueue_print(chunkqueue *cq) {
3228 + for (c = cq->first; c; c = c->next) {
3229 + fprintf(stderr, "(mem) %s", c->mem->ptr + c->offset);
3231 + fprintf(stderr, "\r\n");
3236 + * remove the last chunk if it is empty
3239 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq) {
3241 + if (!cq->last) return;
3242 + if (!cq->first) return;
3244 + if (cq->first == cq->last) {
3247 + if (c->type != MEM_CHUNK) return;
3248 + if (c->mem->used == 0) {
3250 + cq->first = cq->last = NULL;
3255 + for (c = cq->first; c->next; c = c->next) {
3256 + if (c->type != MEM_CHUNK) continue;
3257 + if (c->mem->used != 0) continue;
3259 + if (c->next == cq->last) {
3262 + chunk_free(c->next);
3271 --- ../lighttpd-1.4.11/src/chunk.h 2005-11-01 09:32:21.000000000 +0200
3272 +++ lighttpd-1.4.12/src/chunk.h 2006-07-18 13:03:40.000000000 +0300
3275 typedef struct chunk {
3276 enum { UNUSED_CHUNK, MEM_CHUNK, FILE_CHUNK } type;
3279 buffer *mem; /* either the storage of the mem-chunk or the read-ahead buffer */
3283 off_t length; /* octets to send from the starting offset */
3288 char *start; /* the start pointer of the mmap'ed area */
3289 size_t length; /* size of the mmap'ed area */
3290 - off_t offset; /* start is <n> octet away from the start of the file */
3291 + off_t offset; /* start is <n> octets away from the start of the file */
3294 - int is_temp; /* file is temporary and will be deleted if on cleanup */
3295 + int is_temp; /* file is temporary and will be deleted on cleanup */
3298 - off_t offset; /* octets sent from this chunk
3299 - the size of the chunk is either
3301 + off_t offset; /* octets sent from this chunk
3302 + the size of the chunk is either
3303 - mem-chunk: mem->used - 1
3304 - file-chunk: file.length
3317 size_t unused_chunks;
3320 buffer * chunkqueue_get_append_buffer(chunkqueue *c);
3321 buffer * chunkqueue_get_prepend_buffer(chunkqueue *c);
3322 chunk * chunkqueue_get_append_tempfile(chunkqueue *cq);
3323 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq);
3325 int chunkqueue_remove_finished_chunks(chunkqueue *cq);
3329 int chunkqueue_is_empty(chunkqueue *c);
3331 +void chunkqueue_print(chunkqueue *cq);
3334 --- ../lighttpd-1.4.11/src/configfile-glue.c 2006-03-03 20:14:56.000000000 +0200
3335 +++ lighttpd-1.4.12/src/configfile-glue.c 2006-07-16 00:26:03.000000000 +0300
3343 * are the external interface of lighttpd. The functions
3344 * are used by the server itself and the plugins.
3346 - * The main-goal is to have a small library in the end
3347 - * which is linked against both and which will define
3348 + * The main-goal is to have a small library in the end
3349 + * which is linked against both and which will define
3350 * the interface itself in the end.
3357 int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[]) {
3362 for (i = 0; cv[i].key; i++) {
3365 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3373 switch (cv[i].type) {
3374 case T_CONFIG_ARRAY:
3375 if (du->type == TYPE_ARRAY) {
3377 data_array *da = (data_array *)du;
3380 for (j = 0; j < da->value->used; j++) {
3381 if (da->value->data[j]->type == TYPE_STRING) {
3382 data_string *ds = data_string_init();
3385 buffer_copy_string_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
3386 if (!da->is_index_key) {
3387 /* the id's were generated automaticly, as we copy now we might have to renumber them
3388 - * this is used to prepend server.modules by mod_indexfiles as it has to be loaded
3389 + * this is used to prepend server.modules by mod_indexfiles as it has to be loaded
3390 * before mod_fastcgi and friends */
3391 buffer_copy_string_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
3395 array_insert_unique(cv[i].destination, (data_unset *)ds);
3397 - log_error_write(srv, __FILE__, __LINE__, "sssd",
3398 - "the key of and array can only be a string or a integer, variable:",
3399 - cv[i].key, "type:", da->value->data[j]->type);
3401 + log_error_write(srv, __FILE__, __LINE__, "sssd",
3402 + "the key of and array can only be a string or a integer, variable:",
3403 + cv[i].key, "type:", da->value->data[j]->type);
3409 log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", cv[i].key, "array of strings");
3415 case T_CONFIG_STRING:
3416 if (du->type == TYPE_STRING) {
3417 data_string *ds = (data_string *)du;
3420 buffer_copy_string_buffer(cv[i].destination, ds->value);
3421 + } else if (du->type == TYPE_INTEGER) {
3422 + data_integer *di = (data_integer *)du;
3424 + buffer_copy_long(cv[i].destination, di->value);
3426 log_error_write(srv, __FILE__, __LINE__, "ssss", "unexpected type for key: ", cv[i].key, "(string)", "\"...\"");
3434 case TYPE_INTEGER: {
3435 data_integer *di = (data_integer *)du;
3438 *((unsigned short *)(cv[i].destination)) = di->value;
3442 data_string *ds = (data_string *)du;
3445 + if (buffer_isdigit(ds->value)) {
3446 + *((unsigned short *)(cv[i].destination)) = strtol(ds->value->ptr, NULL, 10);
3450 log_error_write(srv, __FILE__, __LINE__, "ssb", "get a string but expected a short:", cv[i].key, ds->value);
3456 @@ -100,19 +110,19 @@
3457 case T_CONFIG_BOOLEAN:
3458 if (du->type == TYPE_STRING) {
3459 data_string *ds = (data_string *)du;
3462 if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
3463 *((unsigned short *)(cv[i].destination)) = 1;
3464 } else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
3465 *((unsigned short *)(cv[i].destination)) = 0;
3467 log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
3473 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
3481 case T_CONFIG_DEPRECATED:
3482 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
3485 srv->config_deprecated = 1;
3491 @@ -133,25 +143,25 @@
3492 int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
3497 for (i = 0; cv[i].key; i++) {
3498 data_string *touched;
3501 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3510 touched = data_string_init();
3513 buffer_copy_string(touched->value, "");
3514 buffer_copy_string_buffer(touched->key, du->key);
3517 array_insert_unique(srv->config_touched, (data_unset *)touched);
3521 return config_insert_values_internal(srv, ca, cv);
3524 @@ -191,25 +201,25 @@
3527 /* pass the rules */
3531 case COMP_HTTP_HOST: {
3532 char *ck_colon = NULL, *val_colon = NULL;
3535 if (!buffer_is_empty(con->uri.authority)) {
3540 * append server-port to the HTTP_POST if necessary
3544 l = con->uri.authority;
3548 case CONFIG_COND_NE:
3549 case CONFIG_COND_EQ:
3550 ck_colon = strchr(dc->string->ptr, ':');
3551 val_colon = strchr(l->ptr, ':');
3554 if (ck_colon == val_colon) {
3555 /* nothing to do with it */
3557 @@ -230,21 +240,21 @@
3562 + l = srv->empty_string;
3566 case COMP_HTTP_REMOTEIP: {
3568 - /* handle remoteip limitations
3570 + /* handle remoteip limitations
3572 * "10.0.0.1" is provided for all comparisions
3575 * only for == and != we support
3582 if ((dc->cond == CONFIG_COND_EQ ||
3583 dc->cond == CONFIG_COND_NE) &&
3584 (con->dst_addr.plain.sa_family == AF_INET) &&
3585 @@ -253,41 +263,48 @@
3588 struct in_addr val_inp;
3591 + if (con->conf.log_condition_handling) {
3592 + l = srv->empty_string;
3594 + log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key,
3595 + "(", l, ") compare to", dc->string);
3598 if (*(nm_slash+1) == '\0') {
3599 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string);
3602 return COND_RESULT_FALSE;
3606 nm_bits = strtol(nm_slash + 1, &err, 10);
3610 log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, *err);
3613 return COND_RESULT_FALSE;
3617 /* take IP convert to the native */
3618 buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr);
3621 if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) {
3622 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3625 return COND_RESULT_FALSE;
3629 if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) {
3630 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3633 return COND_RESULT_FALSE;
3639 nm = htonl(~((1 << (32 - nm_bits)) - 1));
3642 if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) {
3643 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
3647 case COMP_HTTP_REFERER: {
3651 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
3656 return COND_RESULT_FALSE;
3661 if (con->conf.log_condition_handling) {
3662 log_error_write(srv, __FILE__, __LINE__, "bsbs", dc->comp_key,
3663 @@ -346,10 +363,10 @@
3665 return COND_RESULT_FALSE;
3669 if (con->conf.log_condition_handling) {
3670 log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key,
3671 - "(", l, ") compare to ", dc->string);
3672 + "(", l, ") compare to", dc->string);
3675 case CONFIG_COND_NE:
3676 @@ -365,13 +382,13 @@
3677 case CONFIG_COND_MATCH: {
3678 cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
3683 #define elementsof(x) (sizeof(x) / sizeof(x[0]))
3685 n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0,
3686 cache->matches, elementsof(cache->matches));
3689 cache->patterncount = n;
3691 cache->comp_value = l;
3698 return COND_RESULT_FALSE;
3702 cond_cache_t *caches = con->cond_cache;
3704 if (COND_RESULT_UNSET == caches[dc->context_ndx].result) {
3705 + if (con->conf.log_condition_handling) {
3706 + log_error_write(srv, __FILE__, __LINE__, "sds", "=== start of", dc->context_ndx, "condition block ===");
3708 if (COND_RESULT_TRUE == (caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc))) {
3711 @@ -409,11 +429,11 @@
3713 if (con->conf.log_condition_handling) {
3714 log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3715 - "(uncached) result:",
3717 caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3720 - if (con->conf.log_condition_handling) {
3721 + if (con->conf.log_condition_cache_handling) {
3722 log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3724 caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3728 int config_check_cond(server *srv, connection *con, data_config *dc) {
3729 - if (con->conf.log_condition_handling) {
3730 - log_error_write(srv, __FILE__, __LINE__, "s", "=== start of condition block ===");
3732 return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
3735 @@ -443,3 +460,85 @@
3739 +/* return <0 on error
3740 + * return 0-x if matched (and replaced)
3742 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result)
3746 + pcre_extra *extra;
3747 + const char *pattern;
3748 + size_t pattern_len;
3751 + pcre_keyvalue *kv;
3755 + for (i = 0; i < kvb->used; i++) {
3759 + extra = kv->key_extra;
3760 + pattern = kv->value->ptr;
3761 + pattern_len = kv->value->used - 1;
3763 + if ((n = pcre_exec(match, extra, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
3764 + if (n != PCRE_ERROR_NOMATCH) {
3768 + const char **list;
3769 + size_t start, end;
3773 + pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
3775 + /* search for $[0-9] */
3777 + buffer_reset(result);
3779 + start = 0; end = pattern_len;
3780 + for (k = 0; k < pattern_len; k++) {
3781 + if ((pattern[k] == '$' || pattern[k] == '%') &&
3782 + isdigit((unsigned char)pattern[k + 1])) {
3785 + size_t num = pattern[k + 1] - '0';
3789 + buffer_append_string_len(result, pattern + start, end - start);
3791 + if (pattern[k] == '$') {
3792 + /* n is always > 0 */
3793 + if (num < (size_t)n) {
3794 + buffer_append_string(result, list[num]);
3797 + config_append_cond_match_buffer(con, context, result, num);
3805 + buffer_append_string_len(result, pattern + start, pattern_len - start);
3813 + return PCRE_ERROR_NOMATCH;
3821 --- ../lighttpd-1.4.11/src/configfile.c 2006-02-15 14:26:42.000000000 +0200
3822 +++ lighttpd-1.4.12/src/configfile.c 2006-07-18 13:03:40.000000000 +0300
3827 -#include <unistd.h>
3836 -#include "license.h"
3839 #include "configparser.h"
3840 #include "configfile.h"
3841 #include "proc_open.h"
3843 +#include "sys-files.h"
3844 +#include "sys-process.h"
3848 +#define PATH_MAX 64
3851 static int config_insert(server *srv) {
3854 buffer *stat_cache_string;
3856 - config_values_t cv[] = {
3858 + config_values_t cv[] = {
3859 { "server.bind", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 0 */
3860 { "server.errorlog", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 1 */
3861 { "server.errorfile-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 2 */
3863 { "server.tag", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
3864 { "server.use-ipv6", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
3865 { "server.modules", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER }, /* 9 */
3868 { "server.event-handler", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 10 */
3869 { "server.pid-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 11 */
3870 { "server.max-request-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
3872 { "server.max-keep-alive-requests", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
3873 { "server.name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 18 */
3874 { "server.max-keep-alive-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 19 */
3877 { "server.max-read-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 20 */
3878 { "server.max-write-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 21 */
3879 { "server.error-handler-404", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 22 */
3881 { "mimetype.use-xattr", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 27 */
3882 { "mimetype.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 28 */
3883 { "ssl.pemfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 29 */
3886 { "ssl.engine", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 30 */
3889 { "debug.log-file-not-found", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 31 */
3890 { "debug.log-request-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 32 */
3891 { "debug.log-response-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 33 */
3892 { "debug.log-request-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 34 */
3895 { "server.protocol-http11", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 35 */
3896 { "debug.log-request-header-on-error", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 36 */
3897 { "debug.log-state-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 37 */
3898 { "ssl.ca-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 38 */
3901 { "server.errorlog-use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 39 */
3902 { "server.range-requests", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 40 */
3903 { "server.stat-cache-engine", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 41 */
3905 { "server.network-backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 43 */
3906 { "server.upload-dirs", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 44 */
3907 { "server.core-files", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 45 */
3909 + { "debug.log-condition-cache-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 46 */
3911 { "server.host", "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3912 { "server.docroot", "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3913 { "server.virtual-root", "load mod_simple_vhost and use simple-vhost.server-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3915 { "server.groupid", "use server.groupname instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3916 { "server.use-keep-alive", "use server.max-keep-alive-requests = 0 instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3917 { "server.force-lower-case-files", "use server.force-lowercase-filenames instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3920 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
3926 cv[0].destination = srv->srvconf.bindhost;
3927 cv[1].destination = srv->srvconf.errorlog_file;
3928 @@ -102,33 +105,33 @@
3929 cv[4].destination = srv->srvconf.username;
3930 cv[5].destination = srv->srvconf.groupname;
3931 cv[6].destination = &(srv->srvconf.port);
3934 cv[9].destination = srv->srvconf.modules;
3935 cv[10].destination = srv->srvconf.event_handler;
3936 cv[11].destination = srv->srvconf.pid_file;
3939 cv[13].destination = &(srv->srvconf.max_worker);
3940 cv[23].destination = &(srv->srvconf.max_fds);
3941 cv[36].destination = &(srv->srvconf.log_request_header_on_error);
3942 cv[37].destination = &(srv->srvconf.log_state_handling);
3945 cv[39].destination = &(srv->srvconf.errorlog_use_syslog);
3948 stat_cache_string = buffer_init();
3949 cv[41].destination = stat_cache_string;
3950 cv[43].destination = srv->srvconf.network_backend;
3951 cv[44].destination = srv->srvconf.upload_tempdirs;
3952 cv[45].destination = &(srv->srvconf.enable_cores);
3955 cv[42].destination = &(srv->srvconf.max_conns);
3956 cv[12].destination = &(srv->srvconf.max_request_size);
3957 srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
3959 assert(srv->config_storage);
3962 for (i = 0; i < srv->config_context->used; i++) {
3966 s = calloc(1, sizeof(specific_config));
3968 s->document_root = buffer_init();
3969 @@ -154,17 +157,18 @@
3970 s->global_kbytes_per_second = 0;
3971 s->global_bytes_per_second_cnt = 0;
3972 s->global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
3975 cv[2].destination = s->errorfile_prefix;
3978 cv[7].destination = s->server_tag;
3979 cv[8].destination = &(s->use_ipv6);
3985 cv[14].destination = s->document_root;
3986 cv[15].destination = &(s->force_lowercase_filenames);
3987 cv[16].destination = &(s->log_condition_handling);
3988 + cv[46].destination = &(s->log_condition_cache_handling);
3989 cv[17].destination = &(s->max_keep_alive_requests);
3990 cv[18].destination = s->server_name;
3991 cv[19].destination = &(s->max_keep_alive_idle);
3992 @@ -179,23 +183,23 @@
3993 cv[28].destination = s->mimetypes;
3994 cv[29].destination = s->ssl_pemfile;
3995 cv[30].destination = &(s->is_ssl);
3998 cv[31].destination = &(s->log_file_not_found);
3999 cv[32].destination = &(s->log_request_handling);
4000 cv[33].destination = &(s->log_response_header);
4001 cv[34].destination = &(s->log_request_header);
4004 cv[35].destination = &(s->allow_http11);
4005 cv[38].destination = s->ssl_ca_file;
4006 cv[40].destination = &(s->range_requests);
4009 srv->config_storage[i] = s;
4012 if (0 != (ret = config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv))) {
4018 if (buffer_is_empty(stat_cache_string)) {
4019 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
4020 } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) {
4021 @@ -205,22 +209,22 @@
4022 } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("disable"))) {
4023 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE;
4025 - log_error_write(srv, __FILE__, __LINE__, "sb",
4026 + log_error_write(srv, __FILE__, __LINE__, "sb",
4027 "server.stat-cache-engine can be one of \"disable\", \"simple\", \"fam\", but not:", stat_cache_string);
4028 ret = HANDLER_ERROR;
4032 buffer_free(stat_cache_string);
4041 -#define PATCH(x) con->conf.x = s->x
4043 + con->conf.x = s->x
4044 int config_setup_connection(server *srv, connection *con) {
4045 specific_config *s = srv->config_storage[0];
4048 PATCH(allow_http11);
4050 PATCH(document_root);
4051 @@ -236,20 +240,21 @@
4052 PATCH(kbytes_per_second);
4053 PATCH(global_kbytes_per_second);
4054 PATCH(global_bytes_per_second_cnt);
4057 con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
4058 buffer_copy_string_buffer(con->server_name, s->server_name);
4061 PATCH(log_request_header);
4062 PATCH(log_response_header);
4063 PATCH(log_request_handling);
4064 PATCH(log_condition_handling);
4065 + PATCH(log_condition_cache_handling);
4066 PATCH(log_file_not_found);
4069 PATCH(range_requests);
4070 PATCH(force_lowercase_filenames);
4077 @@ -257,22 +262,22 @@
4079 int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
4083 /* skip the first, the global context */
4084 for (i = 1; i < srv->config_context->used; i++) {
4085 data_config *dc = (data_config *)srv->config_context->data[i];
4086 specific_config *s = srv->config_storage[i];
4090 if (comp != dc->comp) continue;
4093 /* condition didn't match */
4094 if (!config_check_cond(srv, con, dc)) continue;
4098 for (j = 0; j < dc->value->used; j++) {
4099 data_unset *du = dc->value->data[j];
4102 if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.document-root"))) {
4103 PATCH(document_root);
4104 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.range-requests"))) {
4105 @@ -315,11 +320,13 @@
4106 PATCH(log_response_header);
4107 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-handling"))) {
4108 PATCH(log_condition_handling);
4109 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-cache-handling"))) {
4110 + PATCH(log_condition_cache_handling);
4111 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-file-not-found"))) {
4112 PATCH(log_file_not_found);
4113 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
4114 PATCH(allow_http11);
4115 - } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
4116 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
4117 PATCH(force_lowercase_filenames);
4118 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
4119 PATCH(global_kbytes_per_second);
4129 @@ -336,15 +343,15 @@
4135 const buffer *source;
4151 if (0 != stream_open(&(t->s), t->file)) {
4152 - log_error_write(srv, __FILE__, __LINE__, "sbss",
4153 + log_error_write(srv, __FILE__, __LINE__, "sbss",
4154 "opening configfile ", t->file, "failed:", strerror(errno));
4155 buffer_free(t->file);
4158 t->size = t->s.size;
4167 static int config_skip_comment(tokenizer_t *t) {
4169 assert(t->input[t->offset] == '#');
4170 - for (i = 1; t->input[t->offset + i] &&
4171 + for (i = 1; t->input[t->offset + i] &&
4172 (t->input[t->offset + i] != '\n' && t->input[t->offset + i] != '\r');
4175 @@ -411,44 +418,44 @@
4176 static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *token) {
4181 for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
4182 char c = t->input[t->offset];
4183 const char *start = NULL;
4190 if (t->input[t->offset + 1] == '>') {
4194 buffer_copy_string(token, "=>");
4197 tid = TK_ARRAY_ASSIGN;
4199 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4200 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4201 "source:", t->source,
4202 - "line:", t->line, "pos:", t->line_pos,
4203 + "line:", t->line, "pos:", t->line_pos,
4204 "use => for assignments in arrays");
4207 } else if (t->in_cond) {
4208 if (t->input[t->offset + 1] == '=') {
4212 buffer_copy_string(token, "==");
4216 } else if (t->input[t->offset + 1] == '~') {
4220 buffer_copy_string(token, "=~");
4225 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4226 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4227 "source:", t->source,
4228 - "line:", t->line, "pos:", t->line_pos,
4229 + "line:", t->line, "pos:", t->line_pos,
4230 "only =~ and == are allowed in the condition");
4233 @@ -456,51 +463,51 @@
4235 } else if (t->in_key) {
4239 buffer_copy_string_len(token, t->input + t->offset, 1);
4245 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4246 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4247 "source:", t->source,
4248 - "line:", t->line, "pos:", t->line_pos,
4249 + "line:", t->line, "pos:", t->line_pos,
4250 "unexpected equal-sign: =");
4259 if (t->input[t->offset + 1] == '=') {
4263 buffer_copy_string(token, "!=");
4267 } else if (t->input[t->offset + 1] == '~') {
4271 buffer_copy_string(token, "!~");
4276 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4277 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4278 "source:", t->source,
4279 - "line:", t->line, "pos:", t->line_pos,
4280 + "line:", t->line, "pos:", t->line_pos,
4281 "only !~ and != are allowed in the condition");
4287 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4288 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4289 "source:", t->source,
4290 - "line:", t->line, "pos:", t->line_pos,
4291 + "line:", t->line, "pos:", t->line_pos,
4292 "unexpected exclamation-marks: !");
4300 @@ -546,10 +553,10 @@
4302 if (t->in_brace > 0) {
4306 buffer_copy_string(token, "(COMMA)");
4313 @@ -557,70 +564,70 @@
4314 /* search for the terminating " */
4315 start = t->input + t->offset + 1;
4316 buffer_copy_string(token, "");
4319 for (i = 1; t->input[t->offset + i]; i++) {
4320 if (t->input[t->offset + i] == '\\' &&
4321 t->input[t->offset + i + 1] == '"') {
4324 buffer_append_string_len(token, start, t->input + t->offset + i - start);
4327 start = t->input + t->offset + i + 1;
4338 if (t->input[t->offset + i] == '"') {
4342 buffer_append_string_len(token, start, t->input + t->offset + i - start);
4349 if (t->input[t->offset + i] == '\0') {
4352 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4354 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4355 "source:", t->source,
4356 - "line:", t->line, "pos:", t->line_pos,
4357 + "line:", t->line, "pos:", t->line_pos,
4358 "missing closing quote");
4366 t->line_pos += i + 1;
4378 buffer_copy_string(token, "(");
4388 buffer_copy_string(token, ")");
4399 buffer_copy_string(token, "$");
4405 @@ -637,115 +644,107 @@
4414 buffer_copy_string(token, "{");
4427 buffer_copy_string(token, "}");
4439 buffer_copy_string(token, "[");
4452 buffer_copy_string(token, "]");
4457 t->line_pos += config_skip_comment(t);
4463 - for (i = 0; t->input[t->offset + i] &&
4464 + for (i = 0; t->input[t->offset + i] &&
4465 (isalpha((unsigned char)t->input[t->offset + i])
4469 if (i && t->input[t->offset + i]) {
4470 tid = TK_SRVVARNAME;
4471 buffer_copy_string_len(token, t->input + t->offset, i);
4478 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4479 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4480 "source:", t->source,
4481 - "line:", t->line, "pos:", t->line_pos,
4482 + "line:", t->line, "pos:", t->line_pos,
4483 "invalid character in condition");
4486 } else if (isdigit((unsigned char)c)) {
4487 /* take all digits */
4488 for (i = 0; t->input[t->offset + i] && isdigit((unsigned char)t->input[t->offset + i]); i++);
4491 /* was there it least a digit ? */
4492 - if (i && t->input[t->offset + i]) {
4497 buffer_copy_string_len(token, t->input + t->offset, i);
4504 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4505 - "source:", t->source,
4506 - "line:", t->line, "pos:", t->line_pos,
4507 - "unexpected EOF");
4512 /* the key might consist of [-.0-9a-z] */
4513 - for (i = 0; t->input[t->offset + i] &&
4514 - (isalnum((unsigned char)t->input[t->offset + i]) ||
4515 + for (i = 0; t->input[t->offset + i] &&
4516 + (isalnum((unsigned char)t->input[t->offset + i]) ||
4517 t->input[t->offset + i] == '.' ||
4518 t->input[t->offset + i] == '_' || /* for env.* */
4519 t->input[t->offset + i] == '-'
4523 if (i && t->input[t->offset + i]) {
4524 buffer_copy_string_len(token, t->input + t->offset, i);
4526 - if (strcmp(token->ptr, "include") == 0) {
4528 + if (buffer_is_equal_string(token, CONST_STR_LEN("include"))) {
4530 - } else if (strcmp(token->ptr, "include_shell") == 0) {
4531 + } else if (buffer_is_equal_string(token, CONST_STR_LEN("include_shell"))) {
4532 tid = TK_INCLUDE_SHELL;
4533 - } else if (strcmp(token->ptr, "global") == 0) {
4534 + } else if (buffer_is_equal_string(token, CONST_STR_LEN("global"))) {
4536 - } else if (strcmp(token->ptr, "else") == 0) {
4537 + } else if (buffer_is_equal_string(token, CONST_STR_LEN("else"))) {
4548 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4549 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4550 "source:", t->source,
4551 - "line:", t->line, "pos:", t->line_pos,
4552 + "line:", t->line, "pos:", t->line_pos,
4553 "invalid character in variable name");
4556 @@ -753,16 +752,16 @@
4565 - log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
4566 + log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
4567 "source:", t->source,
4568 "line:", t->line, "pos:", t->line_pos,
4569 token, token->used - 1, tid);
4574 } else if (t->offset < t->size) {
4575 fprintf(stderr, "%s.%d: %d, %s\n",
4576 @@ -781,10 +780,11 @@
4577 pParser = configparserAlloc( malloc );
4578 lasttoken = buffer_init();
4579 token = buffer_init();
4581 while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
4582 buffer_copy_string_buffer(lasttoken, token);
4583 configparser(pParser, token_id, token, context);
4586 token = buffer_init();
4589 @@ -797,14 +797,14 @@
4592 configparserFree(pParser, free);
4596 - log_error_write(srv, __FILE__, __LINE__, "sb",
4597 + log_error_write(srv, __FILE__, __LINE__, "sb",
4598 "configfile parser failed:", lasttoken);
4599 } else if (context->ok == 0) {
4600 - log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
4601 + log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
4602 "source:", t->source,
4603 - "line:", t->line, "pos:", t->line_pos,
4604 + "line:", t->line, "pos:", t->line_pos,
4605 "parser failed somehow near here:", lasttoken);
4620 if (0 != stream_open(&s, filename)) {
4621 - log_error_write(srv, __FILE__, __LINE__, "sbss",
4622 + log_error_write(srv, __FILE__, __LINE__, "sbss",
4623 "opening configfile ", filename, "failed:", strerror(errno));
4627 char oldpwd[PATH_MAX];
4629 if (NULL == getcwd(oldpwd, sizeof(oldpwd))) {
4630 - log_error_write(srv, __FILE__, __LINE__, "s",
4631 + log_error_write(srv, __FILE__, __LINE__, "s",
4632 "cannot get cwd", strerror(errno));
4638 if (0 != proc_open_buffer(&proc, cmd, NULL, out, NULL)) {
4639 - log_error_write(srv, __FILE__, __LINE__, "sbss",
4640 + log_error_write(srv, __FILE__, __LINE__, "sbss",
4641 "opening", source, "failed:", strerror(errno));
4644 @@ -896,13 +896,12 @@
4645 static void context_init(server *srv, config_t *context) {
4648 - context->configs_stack = array_init();
4649 - context->configs_stack->is_weakref = 1;
4650 + context->configs_stack = buffer_ptr_init(NULL);
4651 context->basedir = buffer_init();
4654 static void context_free(config_t *context) {
4655 - array_free(context->configs_stack);
4656 + buffer_ptr_free(context->configs_stack);
4657 buffer_free(context->basedir);
4660 @@ -918,18 +917,15 @@
4661 context_init(srv, &context);
4662 context.all_configs = srv->config_context;
4671 + /* use the current dir as basedir for all other includes
4673 + pos = strrchr(fn, DIR_SEPERATOR);
4676 buffer_copy_string_len(context.basedir, fn, pos - fn + 1);
4681 dc = data_config_init();
4682 buffer_copy_string(dc->key, "global");
4685 dpid->value = getpid();
4686 buffer_copy_string(dpid->key, "var.PID");
4687 array_insert_unique(srv->config, (data_unset *)dpid);
4690 dcwd = data_string_init();
4691 buffer_prepare_copy(dcwd->value, 1024);
4692 if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) {
4699 if (NULL != (modules = (data_array *)array_get_element(srv->config, "server.modules"))) {
4701 data_array *prepends;
4702 @@ -1026,22 +1022,23 @@
4703 buffer_copy_string(modules->key, "server.modules");
4704 array_insert_unique(srv->config, (data_unset *)modules);
4709 if (0 != config_insert(srv)) {
4718 int config_set_defaults(server *srv) {
4720 specific_config *s = srv->config_storage[0];
4721 struct stat st1, st2;
4723 - struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
4726 + struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
4728 /* - poll is most reliable
4729 * - select works everywhere
4730 * - linux-* are experimental
4731 @@ -1067,20 +1064,21 @@
4733 { FDEVENT_HANDLER_UNSET, NULL }
4737 - if (buffer_is_empty(s->document_root)) {
4738 - log_error_write(srv, __FILE__, __LINE__, "s",
4739 - "a default document-root has to be set");
4745 + if (buffer_is_empty(s->document_root)) {
4746 + log_error_write(srv, __FILE__, __LINE__, "s",
4747 + "a default document-root has to be set");
4752 if (buffer_is_empty(srv->srvconf.changeroot)) {
4753 - if (-1 == stat(s->document_root->ptr, &st1)) {
4754 - log_error_write(srv, __FILE__, __LINE__, "sb",
4755 + pathname_unix2local(s->document_root);
4756 + if (-1 == stat(s->document_root->ptr, &st1)) {
4757 + log_error_write(srv, __FILE__, __LINE__, "sbs",
4758 "base-docroot doesn't exist:",
4759 - s->document_root);
4760 + s->document_root, strerror(errno));
4764 @@ -1088,18 +1086,18 @@
4765 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.changeroot);
4766 buffer_append_string_buffer(srv->tmp_buf, s->document_root);
4768 - if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
4769 - log_error_write(srv, __FILE__, __LINE__, "sb",
4770 + if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
4771 + log_error_write(srv, __FILE__, __LINE__, "sb",
4772 "base-docroot doesn't exist:",
4781 - buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4783 - buffer_to_lower(srv->tmp_buf);
4784 + buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4786 + buffer_to_lower(srv->tmp_buf);
4788 if (0 == stat(srv->tmp_buf->ptr, &st1)) {
4790 @@ -1107,68 +1105,68 @@
4791 is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);
4793 /* lower-case existed, check upper-case */
4794 - buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4795 + buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4797 - buffer_to_upper(srv->tmp_buf);
4798 + buffer_to_upper(srv->tmp_buf);
4800 /* we have to handle the special case that upper and lower-casing results in the same filename
4801 * as in server.document-root = "/" or "/12345/" */
4803 if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
4804 - /* lower-casing and upper-casing didn't result in
4805 - * an other filename, no need to stat(),
4806 + /* lower-casing and upper-casing didn't result in
4807 + * an other filename, no need to stat(),
4808 * just assume it is case-sensitive. */
4810 s->force_lowercase_filenames = 0;
4811 - } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
4812 + } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
4814 + /* upper case exists too, doesn't the FS handle this ? */
4816 + /* upper and lower have the same inode -> case-insensitve FS */
4818 + if (st1.st_ino == st2.st_ino) {
4819 + /* upper and lower have the same inode -> case-insensitve FS */
4821 + s->force_lowercase_filenames = 1;
4826 - /* upper case exists too, doesn't the FS handle this ? */
4828 - /* upper and lower have the same inode -> case-insensitve FS */
4830 - if (st1.st_ino == st2.st_ino) {
4831 - /* upper and lower have the same inode -> case-insensitve FS */
4833 - s->force_lowercase_filenames = 1;
4838 if (srv->srvconf.port == 0) {
4839 srv->srvconf.port = s->is_ssl ? 443 : 80;
4843 if (srv->srvconf.event_handler->used == 0) {
4844 /* choose a good default
4846 - * the event_handler list is sorted by 'goodness'
4848 + * the event_handler list is sorted by 'goodness'
4849 * taking the first available should be the best solution
4851 srv->event_handler = event_handlers[0].et;
4854 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
4855 - log_error_write(srv, __FILE__, __LINE__, "s",
4856 + log_error_write(srv, __FILE__, __LINE__, "s",
4857 "sorry, there is no event handler for this system");
4868 for (i = 0; event_handlers[i].name; i++) {
4869 if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) {
4870 srv->event_handler = event_handlers[i].et;
4876 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
4877 - log_error_write(srv, __FILE__, __LINE__, "sb",
4878 - "the selected event-handler in unknown or not supported:",
4879 + log_error_write(srv, __FILE__, __LINE__, "sb",
4880 + "the selected event-handler in unknown or not supported:",
4881 srv->srvconf.event_handler );
4887 @@ -1176,19 +1174,19 @@
4889 if (buffer_is_empty(s->ssl_pemfile)) {
4890 /* PEM file is require */
4892 - log_error_write(srv, __FILE__, __LINE__, "s",
4894 + log_error_write(srv, __FILE__, __LINE__, "s",
4895 "ssl.pemfile has to be set");
4901 - log_error_write(srv, __FILE__, __LINE__, "s",
4902 + log_error_write(srv, __FILE__, __LINE__, "s",
4903 "ssl support is missing, recompile with --with-openssl");
4913 --- ../lighttpd-1.4.11/src/configfile.h 2005-08-23 17:36:12.000000000 +0300
4914 +++ lighttpd-1.4.12/src/configfile.h 2006-07-16 00:26:03.000000000 +0300
4919 - array *configs_stack; /* to parse nested block */
4920 + buffer_ptr *configs_stack; /* to parse nested block */
4921 data_config *current; /* current started with { */
4924 --- ../lighttpd-1.4.11/src/configparser.c 2006-02-01 19:51:15.000000000 +0200
4925 +++ lighttpd-1.4.12/src/configparser.c 2006-07-17 22:02:23.000000000 +0300
4927 dc->parent = ctx->current;
4928 array_insert_unique(dc->parent->childs, (data_unset *)dc);
4930 - array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
4931 + buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
4935 static data_config *configparser_pop(config_t *ctx) {
4936 data_config *old = ctx->current;
4937 - ctx->current = (data_config *) array_pop(ctx->configs_stack);
4938 + ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
4942 /* return a copied variable */
4943 static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
4944 - if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
4947 - if (NULL != (env = getenv(key->ptr + 4))) {
4949 - ds = data_string_init();
4950 - buffer_append_string(ds->value, env);
4951 - return (data_unset *)ds;
4954 - fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
4965 - fprintf(stderr, "get var %s\n", key->ptr);
4966 + fprintf(stderr, "get var %s\n", key->ptr);
4968 - for (dc = ctx->current; dc; dc = dc->parent) {
4969 + for (dc = ctx->current; dc; dc = dc->parent) {
4971 - fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
4972 - array_print(dc->value, 0);
4973 + fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
4974 + array_print(dc->value, 0);
4976 - if (NULL != (du = array_get_element(dc->value, key->ptr))) {
4977 - return du->copy(du);
4979 + if (NULL != (du = array_get_element(dc->value, key->ptr))) {
4980 + return du->copy(du);
4982 - fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
4989 /* op1 is to be eat/return by this function, op1->key is not cared
4990 @@ -124,14 +106,14 @@
4994 -#line 128 "configparser.c"
4995 +#line 110 "configparser.c"
4996 /* Next is all token values, in a form suitable for use by makeheaders.
4997 ** This section will be null unless lemon is run with the -m switch.
5001 ** These constants (all generated automatically by the parser generator)
5002 ** specify the various kinds of tokens (terminals) that the parser
5006 ** Each symbol here is a terminal symbol in the grammar.
5009 ** and nonterminals. "int" is used otherwise.
5010 ** YYNOCODE is a number of type YYCODETYPE which corresponds
5011 ** to no legal terminal or nonterminal number. This
5012 -** number is used to fill in empty slots of the hash
5013 +** number is used to fill in empty slots of the hash
5015 ** YYFALLBACK If defined, this indicates that one or more tokens
5016 ** have fall-back values which should be used if the
5018 ** and nonterminal numbers. "unsigned char" is
5019 ** used if there are fewer than 250 rules and
5020 ** states combined. "int" is used otherwise.
5021 -** configparserTOKENTYPE is the data type used for minor tokens given
5022 +** configparserTOKENTYPE is the data type used for minor tokens given
5023 ** directly to the parser from the tokenizer.
5024 ** YYMINORTYPE is the data type used for all minor tokens.
5025 ** This is typically a union of many types, one of
5027 #define configparserARG_PDECL ,config_t *ctx
5028 #define configparserARG_FETCH config_t *ctx = yypParser->ctx
5029 #define configparserARG_STORE yypParser->ctx = ctx
5030 -#define YYNSTATE 62
5032 +#define YYNSTATE 63
5034 #define YYERRORSYMBOL 26
5035 #define YYERRSYMDT yy95
5036 #define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
5038 /* Next are that tables used to determine what action to take based on the
5039 ** current state and lookahead token. These tables are used to implement
5040 ** functions that take a state number and lookahead value and return an
5044 ** Suppose the action integer is N. Then the action is determined as
5047 ** If the index value yy_shift_ofst[S]+X is out of range or if the value
5048 ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
5049 ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
5050 -** and that yy_default[S] should be used instead.
5051 +** and that yy_default[S] should be used instead.
5053 ** The formula above is for computing the action when the lookahead is
5054 ** a terminal symbol. If the lookahead is a non-terminal (as occurs after
5055 @@ -248,67 +230,69 @@
5056 ** yy_default[] Default action for each state.
5058 static YYACTIONTYPE yy_action[] = {
5059 - /* 0 */ 2, 3, 4, 5, 13, 14, 62, 15, 7, 44,
5060 - /* 10 */ 20, 86, 16, 45, 28, 48, 40, 10, 39, 25,
5061 - /* 20 */ 22, 49, 45, 8, 15, 102, 1, 20, 28, 18,
5062 - /* 30 */ 57, 59, 19, 25, 22, 39, 19, 61, 98, 45,
5063 - /* 40 */ 20, 6, 23, 24, 26, 28, 35, 57, 59, 12,
5064 - /* 50 */ 25, 22, 28, 27, 36, 87, 29, 25, 22, 33,
5065 - /* 60 */ 15, 30, 31, 20, 28, 38, 9, 17, 37, 25,
5066 - /* 70 */ 22, 39, 42, 43, 10, 45, 11, 53, 54, 55,
5067 - /* 80 */ 56, 28, 52, 57, 59, 34, 25, 22, 28, 27,
5068 - /* 90 */ 32, 88, 41, 25, 22, 33, 28, 48, 46, 28,
5069 - /* 100 */ 48, 25, 22, 58, 25, 22, 60, 21, 19, 47,
5070 - /* 110 */ 51, 50, 25, 22, 88, 88, 93,
5071 + /* 0 */ 2, 3, 4, 5, 13, 14, 63, 15, 7, 45,
5072 + /* 10 */ 20, 88, 16, 46, 28, 49, 41, 10, 40, 25,
5073 + /* 20 */ 22, 50, 46, 8, 15, 104, 1, 20, 28, 18,
5074 + /* 30 */ 58, 60, 6, 25, 22, 40, 47, 62, 11, 46,
5075 + /* 40 */ 20, 9, 23, 24, 26, 29, 89, 58, 60, 10,
5076 + /* 50 */ 17, 38, 28, 27, 37, 19, 30, 25, 22, 34,
5077 + /* 60 */ 15, 100, 20, 20, 23, 24, 26, 12, 19, 31,
5078 + /* 70 */ 32, 40, 19, 44, 43, 46, 95, 35, 90, 89,
5079 + /* 80 */ 28, 49, 42, 58, 60, 25, 22, 59, 28, 27,
5080 + /* 90 */ 33, 48, 52, 25, 22, 34, 28, 49, 51, 28,
5081 + /* 100 */ 36, 25, 22, 61, 25, 22, 89, 28, 39, 89,
5082 + /* 110 */ 89, 89, 25, 22, 54, 55, 56, 57, 89, 28,
5083 + /* 120 */ 53, 21, 89, 89, 25, 22, 25, 22,
5085 static YYCODETYPE yy_lookahead[] = {
5086 /* 0 */ 29, 30, 31, 32, 33, 34, 0, 1, 44, 38,
5087 /* 10 */ 4, 15, 41, 16, 35, 36, 45, 46, 12, 40,
5088 /* 20 */ 41, 42, 16, 15, 1, 27, 28, 4, 35, 36,
5089 - /* 30 */ 24, 25, 5, 40, 41, 12, 5, 14, 11, 16,
5090 - /* 40 */ 4, 1, 6, 7, 8, 35, 36, 24, 25, 28,
5091 - /* 50 */ 40, 41, 35, 36, 37, 15, 39, 40, 41, 42,
5092 - /* 60 */ 1, 9, 10, 4, 35, 36, 38, 2, 3, 40,
5093 - /* 70 */ 41, 12, 28, 14, 46, 16, 13, 20, 21, 22,
5094 - /* 80 */ 23, 35, 36, 24, 25, 11, 40, 41, 35, 36,
5095 - /* 90 */ 37, 13, 13, 40, 41, 42, 35, 36, 17, 35,
5096 - /* 100 */ 36, 40, 41, 42, 40, 41, 42, 35, 5, 18,
5097 - /* 110 */ 43, 19, 40, 41, 47, 47, 13,
5098 + /* 30 */ 24, 25, 1, 40, 41, 12, 17, 14, 13, 16,
5099 + /* 40 */ 4, 38, 6, 7, 8, 9, 15, 24, 25, 46,
5100 + /* 50 */ 2, 3, 35, 36, 37, 5, 39, 40, 41, 42,
5101 + /* 60 */ 1, 11, 4, 4, 6, 7, 8, 28, 5, 9,
5102 + /* 70 */ 10, 12, 5, 14, 28, 16, 13, 11, 13, 47,
5103 + /* 80 */ 35, 36, 13, 24, 25, 40, 41, 42, 35, 36,
5104 + /* 90 */ 37, 18, 43, 40, 41, 42, 35, 36, 19, 35,
5105 + /* 100 */ 36, 40, 41, 42, 40, 41, 47, 35, 36, 47,
5106 + /* 110 */ 47, 47, 40, 41, 20, 21, 22, 23, 47, 35,
5107 + /* 120 */ 36, 35, 47, 47, 40, 41, 40, 41,
5109 #define YY_SHIFT_USE_DFLT (-5)
5110 static signed char yy_shift_ofst[] = {
5111 - /* 0 */ -5, 6, -5, -5, -5, 40, -4, 8, -3, -5,
5112 - /* 10 */ 63, -5, 23, -5, -5, -5, 65, 36, 31, 36,
5113 - /* 20 */ -5, -5, -5, -5, -5, -5, 36, 27, -5, 52,
5114 - /* 30 */ -5, 36, -5, 74, 36, 31, -5, 36, 31, 78,
5115 - /* 40 */ 79, -5, 59, -5, -5, 81, 91, 36, 31, 92,
5116 - /* 50 */ 57, 36, 103, -5, -5, -5, -5, 36, -5, 36,
5118 + /* 0 */ -5, 6, -5, -5, -5, 31, -4, 8, -3, -5,
5119 + /* 10 */ 25, -5, 23, -5, -5, -5, 48, 58, 67, 58,
5120 + /* 20 */ -5, -5, -5, -5, -5, -5, 36, 50, -5, -5,
5121 + /* 30 */ 60, -5, 58, -5, 66, 58, 67, -5, 58, 67,
5122 + /* 40 */ 65, 69, -5, 59, -5, -5, 19, 73, 58, 67,
5123 + /* 50 */ 79, 94, 58, 63, -5, -5, -5, -5, 58, -5,
5124 + /* 60 */ 58, -5, -5,
5126 #define YY_REDUCE_USE_DFLT (-37)
5127 static signed char yy_reduce_ofst[] = {
5128 - /* 0 */ -2, -29, -37, -37, -37, -36, -37, -37, 28, -37,
5129 - /* 10 */ -37, 21, -29, -37, -37, -37, -37, -7, -37, 72,
5130 + /* 0 */ -2, -29, -37, -37, -37, -36, -37, -37, 3, -37,
5131 + /* 10 */ -37, 39, -29, -37, -37, -37, -37, -7, -37, 86,
5132 /* 20 */ -37, -37, -37, -37, -37, -37, 17, -37, -37, -37,
5133 - /* 30 */ -37, 53, -37, -37, 10, -37, -37, 29, -37, -37,
5134 - /* 40 */ -37, 44, -29, -37, -37, -37, -37, -21, -37, -37,
5135 - /* 50 */ 67, 46, -37, -37, -37, -37, -37, 61, -37, 64,
5136 - /* 60 */ -37, -37,
5137 + /* 30 */ -37, -37, 53, -37, -37, 64, -37, -37, 72, -37,
5138 + /* 40 */ -37, -37, 46, -29, -37, -37, -37, -37, -21, -37,
5139 + /* 50 */ -37, 49, 84, -37, -37, -37, -37, -37, 45, -37,
5140 + /* 60 */ 61, -37, -37,
5142 static YYACTIONTYPE yy_default[] = {
5143 - /* 0 */ 64, 101, 63, 65, 66, 101, 67, 101, 101, 90,
5144 - /* 10 */ 101, 64, 101, 68, 69, 70, 101, 101, 71, 101,
5145 - /* 20 */ 73, 74, 76, 77, 78, 79, 101, 84, 75, 101,
5146 - /* 30 */ 80, 82, 81, 101, 101, 85, 83, 101, 72, 101,
5147 - /* 40 */ 101, 64, 101, 89, 91, 101, 101, 101, 98, 101,
5148 - /* 50 */ 101, 101, 101, 94, 95, 96, 97, 101, 99, 101,
5150 + /* 0 */ 65, 103, 64, 66, 67, 103, 68, 103, 103, 92,
5151 + /* 10 */ 103, 65, 103, 69, 70, 71, 103, 103, 72, 103,
5152 + /* 20 */ 74, 75, 77, 78, 79, 80, 103, 86, 76, 81,
5153 + /* 30 */ 103, 82, 84, 83, 103, 103, 87, 85, 103, 73,
5154 + /* 40 */ 103, 103, 65, 103, 91, 93, 103, 103, 103, 100,
5155 + /* 50 */ 103, 103, 103, 103, 96, 97, 98, 99, 103, 101,
5156 + /* 60 */ 103, 102, 94,
5158 #define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
5160 /* The next table maps tokens into fallback tokens. If a construct
5161 ** like the following:
5164 ** %fallback ID X Y Z.
5166 ** appears in the grammer, then ID becomes a fallback token for X, Y,
5167 @@ -359,10 +343,10 @@
5173 ** Turn parser tracing on by giving a stream to which to write the trace
5174 ** and a prompt to preface each trace message. Tracing is turned off
5175 -** by making either argument NULL
5176 +** by making either argument NULL
5182 /* For tracing shifts, the names of all terminals and nonterminals
5183 ** are required. The following table supplies these names */
5184 -static const char *yyTokenName[] = {
5185 +static const char *yyTokenName[] = {
5186 "$", "EOL", "ASSIGN", "APPEND",
5187 "LKEY", "PLUS", "STRING", "INTEGER",
5188 "LPARAN", "RPARAN", "COMMA", "ARRAY_ASSIGN",
5189 @@ -425,27 +409,28 @@
5190 /* 15 */ "value ::= STRING",
5191 /* 16 */ "value ::= INTEGER",
5192 /* 17 */ "value ::= array",
5193 - /* 18 */ "array ::= LPARAN aelements RPARAN",
5194 - /* 19 */ "aelements ::= aelements COMMA aelement",
5195 - /* 20 */ "aelements ::= aelements COMMA",
5196 - /* 21 */ "aelements ::= aelement",
5197 - /* 22 */ "aelement ::= expression",
5198 - /* 23 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5199 - /* 24 */ "eols ::= EOL",
5200 - /* 25 */ "eols ::=",
5201 - /* 26 */ "globalstart ::= GLOBAL",
5202 - /* 27 */ "global ::= globalstart LCURLY metalines RCURLY",
5203 - /* 28 */ "condlines ::= condlines eols ELSE condline",
5204 - /* 29 */ "condlines ::= condline",
5205 - /* 30 */ "condline ::= context LCURLY metalines RCURLY",
5206 - /* 31 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5207 - /* 32 */ "cond ::= EQ",
5208 - /* 33 */ "cond ::= MATCH",
5209 - /* 34 */ "cond ::= NE",
5210 - /* 35 */ "cond ::= NOMATCH",
5211 - /* 36 */ "stringop ::= expression",
5212 - /* 37 */ "include ::= INCLUDE stringop",
5213 - /* 38 */ "include_shell ::= INCLUDE_SHELL stringop",
5214 + /* 18 */ "array ::= LPARAN RPARAN",
5215 + /* 19 */ "array ::= LPARAN aelements RPARAN",
5216 + /* 20 */ "aelements ::= aelements COMMA aelement",
5217 + /* 21 */ "aelements ::= aelements COMMA",
5218 + /* 22 */ "aelements ::= aelement",
5219 + /* 23 */ "aelement ::= expression",
5220 + /* 24 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5221 + /* 25 */ "eols ::= EOL",
5222 + /* 26 */ "eols ::=",
5223 + /* 27 */ "globalstart ::= GLOBAL",
5224 + /* 28 */ "global ::= globalstart LCURLY metalines RCURLY",
5225 + /* 29 */ "condlines ::= condlines eols ELSE condline",
5226 + /* 30 */ "condlines ::= condline",
5227 + /* 31 */ "condline ::= context LCURLY metalines RCURLY",
5228 + /* 32 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5229 + /* 33 */ "cond ::= EQ",
5230 + /* 34 */ "cond ::= MATCH",
5231 + /* 35 */ "cond ::= NE",
5232 + /* 36 */ "cond ::= NOMATCH",
5233 + /* 37 */ "stringop ::= expression",
5234 + /* 38 */ "include ::= INCLUDE stringop",
5235 + /* 39 */ "include_shell ::= INCLUDE_SHELL stringop",
5245 ** This function allocates a new parser.
5246 ** The only argument is a pointer to a function which works like
5249 /* Here is inserted the actions which take place when a
5250 ** terminal or non-terminal is destroyed. This can happen
5251 ** when the symbol is popped from the stack during a
5252 - ** reduce or during error processing or when a parser is
5253 + ** reduce or during error processing or when a parser is
5254 ** being destroyed before it is finished parsing.
5256 ** Note: during a reduce, the only symbols destroyed are those
5257 @@ -528,44 +513,44 @@
5261 -#line 160 "./configparser.y"
5262 +#line 143 "./configparser.y"
5263 { buffer_free((yypminor->yy0)); }
5264 -#line 533 "configparser.c"
5265 +#line 518 "configparser.c"
5268 -#line 151 "./configparser.y"
5269 +#line 134 "./configparser.y"
5270 { (yypminor->yy41)->free((yypminor->yy41)); }
5271 -#line 538 "configparser.c"
5272 +#line 523 "configparser.c"
5275 -#line 152 "./configparser.y"
5276 +#line 135 "./configparser.y"
5277 { (yypminor->yy41)->free((yypminor->yy41)); }
5278 -#line 543 "configparser.c"
5279 +#line 528 "configparser.c"
5282 -#line 153 "./configparser.y"
5283 +#line 136 "./configparser.y"
5284 { (yypminor->yy41)->free((yypminor->yy41)); }
5285 -#line 548 "configparser.c"
5286 +#line 533 "configparser.c"
5289 -#line 154 "./configparser.y"
5290 +#line 137 "./configparser.y"
5291 { array_free((yypminor->yy40)); }
5292 -#line 553 "configparser.c"
5293 +#line 538 "configparser.c"
5296 -#line 155 "./configparser.y"
5297 +#line 138 "./configparser.y"
5298 { array_free((yypminor->yy40)); }
5299 -#line 558 "configparser.c"
5300 +#line 543 "configparser.c"
5303 -#line 156 "./configparser.y"
5304 +#line 139 "./configparser.y"
5305 { buffer_free((yypminor->yy43)); }
5306 -#line 563 "configparser.c"
5307 +#line 548 "configparser.c"
5310 -#line 157 "./configparser.y"
5311 +#line 140 "./configparser.y"
5312 { buffer_free((yypminor->yy43)); }
5313 -#line 568 "configparser.c"
5314 +#line 553 "configparser.c"
5316 default: break; /* If no destructor action specified: do nothing */
5324 ** Deallocate and destroy a parser. Destructors are all called for
5325 ** all stack elements before shutting the parser down.
5330 int stateno = pParser->yystack[pParser->yyidx].stateno;
5333 /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
5334 i = yy_shift_ofst[stateno];
5335 if( i==YY_SHIFT_USE_DFLT ){
5339 int stateno = pParser->yystack[pParser->yyidx].stateno;
5342 i = yy_reduce_ofst[stateno];
5343 if( i==YY_REDUCE_USE_DFLT ){
5344 return yy_default[stateno];
5354 configparserARG_FETCH;
5355 yymsp = &yypParser->yystack[yypParser->yyidx];
5357 - if( yyTraceFILE && yyruleno>=0
5358 + if( yyTraceFILE && yyruleno>=0
5359 && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
5360 fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
5361 yyRuleName[yyruleno]);
5363 /* No destructor defined for global */
5366 -#line 134 "./configparser.y"
5367 +#line 116 "./configparser.y"
5368 { yymsp[-1].minor.yy78 = NULL; }
5369 -#line 837 "configparser.c"
5370 +#line 823 "configparser.c"
5371 yy_destructor(1,&yymsp[0].minor);
5374 @@ -847,10 +833,15 @@
5375 yy_destructor(1,&yymsp[0].minor);
5378 -#line 162 "./configparser.y"
5379 +#line 145 "./configparser.y"
5381 buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5382 - if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5383 + if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5384 + fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
5385 + ctx->current->context_ndx,
5386 + ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5388 + } else if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5389 array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5390 yymsp[0].minor.yy41 = NULL;
5392 @@ -864,16 +855,21 @@
5393 buffer_free(yymsp[-2].minor.yy43);
5394 yymsp[-2].minor.yy43 = NULL;
5396 -#line 867 "configparser.c"
5397 +#line 858 "configparser.c"
5398 yy_destructor(2,&yymsp[-1].minor);
5401 -#line 179 "./configparser.y"
5402 +#line 167 "./configparser.y"
5404 array *vars = ctx->current->value;
5407 - if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5408 + if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5409 + fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
5410 + ctx->current->context_ndx,
5411 + ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5413 + } else if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5414 /* exists in current block */
5415 du = configparser_merge_data(du, yymsp[0].minor.yy41);
5418 buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5419 array_replace(vars, du);
5421 + yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5422 } else if (NULL != (du = configparser_get_variable(ctx, yymsp[-2].minor.yy43))) {
5423 du = configparser_merge_data(du, yymsp[0].minor.yy41);
5425 @@ -892,22 +889,20 @@
5426 buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5427 array_insert_unique(ctx->current->value, du);
5429 + yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5431 - fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n",
5432 - ctx->current->context_ndx,
5433 - ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5435 + buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5436 + array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5438 buffer_free(yymsp[-2].minor.yy43);
5439 yymsp[-2].minor.yy43 = NULL;
5440 - yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5441 yymsp[0].minor.yy41 = NULL;
5443 -#line 906 "configparser.c"
5444 +#line 901 "configparser.c"
5445 yy_destructor(3,&yymsp[-1].minor);
5448 -#line 214 "./configparser.y"
5449 +#line 206 "./configparser.y"
5451 if (strchr(yymsp[0].minor.yy0->ptr, '.') == NULL) {
5452 yygotominor.yy43 = buffer_init_string("var.");
5453 @@ -919,10 +914,10 @@
5454 yymsp[0].minor.yy0 = NULL;
5457 -#line 922 "configparser.c"
5458 +#line 917 "configparser.c"
5461 -#line 226 "./configparser.y"
5462 +#line 218 "./configparser.y"
5464 yygotominor.yy41 = configparser_merge_data(yymsp[-2].minor.yy41, yymsp[0].minor.yy41);
5465 if (NULL == yygotominor.yy41) {
5466 @@ -932,21 +927,38 @@
5467 yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5468 yymsp[0].minor.yy41 = NULL;
5470 -#line 935 "configparser.c"
5471 +#line 930 "configparser.c"
5472 yy_destructor(5,&yymsp[-1].minor);
5475 -#line 236 "./configparser.y"
5476 +#line 228 "./configparser.y"
5478 yygotominor.yy41 = yymsp[0].minor.yy41;
5479 yymsp[0].minor.yy41 = NULL;
5481 -#line 944 "configparser.c"
5482 +#line 939 "configparser.c"
5485 -#line 241 "./configparser.y"
5486 +#line 233 "./configparser.y"
5488 - yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43);
5489 + if (strncmp(yymsp[0].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5492 + if (NULL != (env = getenv(yymsp[0].minor.yy43->ptr + 4))) {
5494 + ds = data_string_init();
5495 + buffer_append_string(ds->value, env);
5496 + yygotominor.yy41 = (data_unset *)ds;
5499 + yygotominor.yy41 = NULL;
5500 + fprintf(stderr, "Undefined env variable: %s\n", yymsp[0].minor.yy43->ptr + 4);
5503 + } else if (NULL == (yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43))) {
5504 + fprintf(stderr, "Undefined config variable: %s\n", yymsp[0].minor.yy43->ptr);
5507 if (!yygotominor.yy41) {
5508 /* make a dummy so it won't crash */
5509 yygotominor.yy41 = (data_unset *)data_string_init();
5510 @@ -954,50 +966,59 @@
5511 buffer_free(yymsp[0].minor.yy43);
5512 yymsp[0].minor.yy43 = NULL;
5514 -#line 957 "configparser.c"
5515 +#line 969 "configparser.c"
5518 -#line 251 "./configparser.y"
5519 +#line 260 "./configparser.y"
5521 yygotominor.yy41 = (data_unset *)data_string_init();
5522 buffer_copy_string_buffer(((data_string *)(yygotominor.yy41))->value, yymsp[0].minor.yy0);
5523 buffer_free(yymsp[0].minor.yy0);
5524 yymsp[0].minor.yy0 = NULL;
5526 -#line 967 "configparser.c"
5527 +#line 979 "configparser.c"
5530 -#line 258 "./configparser.y"
5531 +#line 267 "./configparser.y"
5533 yygotominor.yy41 = (data_unset *)data_integer_init();
5534 ((data_integer *)(yygotominor.yy41))->value = strtol(yymsp[0].minor.yy0->ptr, NULL, 10);
5535 buffer_free(yymsp[0].minor.yy0);
5536 yymsp[0].minor.yy0 = NULL;
5538 -#line 977 "configparser.c"
5539 +#line 989 "configparser.c"
5542 -#line 264 "./configparser.y"
5543 +#line 273 "./configparser.y"
5545 yygotominor.yy41 = (data_unset *)data_array_init();
5546 array_free(((data_array *)(yygotominor.yy41))->value);
5547 ((data_array *)(yygotominor.yy41))->value = yymsp[0].minor.yy40;
5548 yymsp[0].minor.yy40 = NULL;
5550 -#line 987 "configparser.c"
5551 +#line 999 "configparser.c"
5554 -#line 270 "./configparser.y"
5555 +#line 279 "./configparser.y"
5557 + yygotominor.yy40 = array_init();
5559 +#line 1006 "configparser.c"
5560 + yy_destructor(8,&yymsp[-1].minor);
5561 + yy_destructor(9,&yymsp[0].minor);
5564 +#line 282 "./configparser.y"
5566 yygotominor.yy40 = yymsp[-1].minor.yy40;
5567 yymsp[-1].minor.yy40 = NULL;
5569 -#line 995 "configparser.c"
5570 +#line 1016 "configparser.c"
5571 yy_destructor(8,&yymsp[-2].minor);
5572 yy_destructor(9,&yymsp[0].minor);
5575 -#line 275 "./configparser.y"
5577 +#line 287 "./configparser.y"
5579 if (buffer_is_empty(yymsp[0].minor.yy41->key) ||
5580 NULL == array_get_element(yymsp[-2].minor.yy40, yymsp[0].minor.yy41->key->ptr)) {
5581 @@ -1014,37 +1035,37 @@
5582 yygotominor.yy40 = yymsp[-2].minor.yy40;
5583 yymsp[-2].minor.yy40 = NULL;
5585 -#line 1017 "configparser.c"
5586 +#line 1038 "configparser.c"
5587 yy_destructor(10,&yymsp[-1].minor);
5590 -#line 292 "./configparser.y"
5592 +#line 304 "./configparser.y"
5594 yygotominor.yy40 = yymsp[-1].minor.yy40;
5595 yymsp[-1].minor.yy40 = NULL;
5597 -#line 1026 "configparser.c"
5598 +#line 1047 "configparser.c"
5599 yy_destructor(10,&yymsp[0].minor);
5602 -#line 297 "./configparser.y"
5604 +#line 309 "./configparser.y"
5606 yygotominor.yy40 = array_init();
5607 array_insert_unique(yygotominor.yy40, yymsp[0].minor.yy41);
5608 yymsp[0].minor.yy41 = NULL;
5610 -#line 1036 "configparser.c"
5611 +#line 1057 "configparser.c"
5614 -#line 303 "./configparser.y"
5616 +#line 315 "./configparser.y"
5618 yygotominor.yy41 = yymsp[0].minor.yy41;
5619 yymsp[0].minor.yy41 = NULL;
5621 -#line 1044 "configparser.c"
5622 +#line 1065 "configparser.c"
5625 -#line 307 "./configparser.y"
5627 +#line 319 "./configparser.y"
5629 buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5630 buffer_free(yymsp[-2].minor.yy43);
5631 @@ -1053,27 +1074,27 @@
5632 yygotominor.yy41 = yymsp[0].minor.yy41;
5633 yymsp[0].minor.yy41 = NULL;
5635 -#line 1056 "configparser.c"
5636 +#line 1077 "configparser.c"
5637 yy_destructor(11,&yymsp[-1].minor);
5640 - yy_destructor(1,&yymsp[0].minor);
5643 + yy_destructor(1,&yymsp[0].minor);
5646 -#line 319 "./configparser.y"
5649 +#line 331 "./configparser.y"
5652 dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
5654 configparser_push(ctx, dc, 0);
5656 -#line 1072 "configparser.c"
5657 +#line 1093 "configparser.c"
5658 yy_destructor(12,&yymsp[0].minor);
5661 -#line 326 "./configparser.y"
5663 +#line 338 "./configparser.y"
5667 @@ -1082,16 +1103,16 @@
5669 assert(cur && ctx->current);
5671 - yygotominor.yy0 = cur;
5672 + yygotominor.yy78 = cur;
5674 -#line 1087 "configparser.c"
5675 +#line 1108 "configparser.c"
5676 /* No destructor defined for globalstart */
5677 yy_destructor(13,&yymsp[-2].minor);
5678 /* No destructor defined for metalines */
5679 yy_destructor(14,&yymsp[0].minor);
5682 -#line 337 "./configparser.y"
5684 +#line 349 "./configparser.y"
5686 assert(yymsp[-3].minor.yy78->context_ndx < yymsp[0].minor.yy78->context_ndx);
5687 yymsp[0].minor.yy78->prev = yymsp[-3].minor.yy78;
5688 @@ -1100,20 +1121,20 @@
5689 yymsp[-3].minor.yy78 = NULL;
5690 yymsp[0].minor.yy78 = NULL;
5692 -#line 1103 "configparser.c"
5693 +#line 1124 "configparser.c"
5694 /* No destructor defined for eols */
5695 yy_destructor(15,&yymsp[-1].minor);
5698 -#line 346 "./configparser.y"
5700 +#line 358 "./configparser.y"
5702 yygotominor.yy78 = yymsp[0].minor.yy78;
5703 yymsp[0].minor.yy78 = NULL;
5705 -#line 1113 "configparser.c"
5706 +#line 1134 "configparser.c"
5709 -#line 351 "./configparser.y"
5711 +#line 363 "./configparser.y"
5715 @@ -1124,14 +1145,14 @@
5717 yygotominor.yy78 = cur;
5719 -#line 1127 "configparser.c"
5720 +#line 1148 "configparser.c"
5721 /* No destructor defined for context */
5722 yy_destructor(13,&yymsp[-2].minor);
5723 /* No destructor defined for metalines */
5724 yy_destructor(14,&yymsp[0].minor);
5727 -#line 362 "./configparser.y"
5729 +#line 374 "./configparser.y"
5732 buffer *b, *rvalue, *op;
5733 @@ -1266,45 +1287,45 @@
5734 yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5735 yymsp[0].minor.yy41 = NULL;
5737 -#line 1269 "configparser.c"
5738 +#line 1290 "configparser.c"
5739 yy_destructor(16,&yymsp[-6].minor);
5740 yy_destructor(18,&yymsp[-4].minor);
5741 yy_destructor(19,&yymsp[-2].minor);
5744 -#line 496 "./configparser.y"
5746 +#line 508 "./configparser.y"
5748 yygotominor.yy27 = CONFIG_COND_EQ;
5750 -#line 1279 "configparser.c"
5751 +#line 1300 "configparser.c"
5752 yy_destructor(20,&yymsp[0].minor);
5755 -#line 499 "./configparser.y"
5757 +#line 511 "./configparser.y"
5759 yygotominor.yy27 = CONFIG_COND_MATCH;
5761 -#line 1287 "configparser.c"
5762 +#line 1308 "configparser.c"
5763 yy_destructor(21,&yymsp[0].minor);
5766 -#line 502 "./configparser.y"
5768 +#line 514 "./configparser.y"
5770 yygotominor.yy27 = CONFIG_COND_NE;
5772 -#line 1295 "configparser.c"
5773 +#line 1316 "configparser.c"
5774 yy_destructor(22,&yymsp[0].minor);
5777 -#line 505 "./configparser.y"
5779 +#line 517 "./configparser.y"
5781 yygotominor.yy27 = CONFIG_COND_NOMATCH;
5783 -#line 1303 "configparser.c"
5784 +#line 1324 "configparser.c"
5785 yy_destructor(23,&yymsp[0].minor);
5788 -#line 509 "./configparser.y"
5790 +#line 521 "./configparser.y"
5792 yygotominor.yy43 = NULL;
5794 @@ -1321,10 +1342,10 @@
5795 yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5796 yymsp[0].minor.yy41 = NULL;
5798 -#line 1324 "configparser.c"
5799 +#line 1345 "configparser.c"
5802 -#line 526 "./configparser.y"
5804 +#line 538 "./configparser.y"
5807 if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
5808 @@ -1334,11 +1355,11 @@
5809 yymsp[0].minor.yy43 = NULL;
5812 -#line 1337 "configparser.c"
5813 +#line 1358 "configparser.c"
5814 yy_destructor(24,&yymsp[-1].minor);
5817 -#line 536 "./configparser.y"
5819 +#line 548 "./configparser.y"
5822 if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
5823 @@ -1348,7 +1369,7 @@
5824 yymsp[0].minor.yy43 = NULL;
5827 -#line 1351 "configparser.c"
5828 +#line 1372 "configparser.c"
5829 yy_destructor(25,&yymsp[-1].minor);
5832 @@ -1378,11 +1399,11 @@
5833 while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
5834 /* Here code is inserted which will be executed whenever the
5836 -#line 125 "./configparser.y"
5837 +#line 107 "./configparser.y"
5841 -#line 1385 "configparser.c"
5842 +#line 1406 "configparser.c"
5843 configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
5846 @@ -1489,7 +1510,7 @@
5847 #ifdef YYERRORSYMBOL
5848 /* A syntax error has occurred.
5849 ** The response to an error depends upon whether or not the
5850 - ** grammar defines an error token "ERROR".
5851 + ** grammar defines an error token "ERROR".
5853 ** This is what we do if the grammar does define ERROR:
5855 --- ../lighttpd-1.4.11/src/configparser.y 2006-01-26 18:46:25.000000000 +0200
5856 +++ lighttpd-1.4.12/src/configparser.y 2006-07-16 00:26:04.000000000 +0300
5858 dc->parent = ctx->current;
5859 array_insert_unique(dc->parent->childs, (data_unset *)dc);
5861 - array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
5862 + buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
5866 static data_config *configparser_pop(config_t *ctx) {
5867 data_config *old = ctx->current;
5868 - ctx->current = (data_config *) array_pop(ctx->configs_stack);
5869 + ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
5873 /* return a copied variable */
5874 static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
5875 - if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
5878 - if (NULL != (env = getenv(key->ptr + 4))) {
5880 - ds = data_string_init();
5881 - buffer_append_string(ds->value, env);
5882 - return (data_unset *)ds;
5885 - fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
5896 - fprintf(stderr, "get var %s\n", key->ptr);
5897 + fprintf(stderr, "get var %s\n", key->ptr);
5899 - for (dc = ctx->current; dc; dc = dc->parent) {
5900 + for (dc = ctx->current; dc; dc = dc->parent) {
5902 - fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5903 - array_print(dc->value, 0);
5904 + fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5905 + array_print(dc->value, 0);
5907 - if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5908 - return du->copy(du);
5910 + if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5911 + return du->copy(du);
5913 - fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
5920 /* op1 is to be eat/return by this function, op1->key is not cared
5922 %type aelement {data_unset *}
5923 %type condline {data_config *}
5924 %type condlines {data_config *}
5925 +%type global {data_config *}
5926 %type aelements {array *}
5927 %type array {array *}
5928 %type key {buffer *}
5929 @@ -161,7 +144,12 @@
5931 varline ::= key(A) ASSIGN expression(B). {
5932 buffer_copy_string_buffer(B->key, A);
5933 - if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
5934 + if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
5935 + fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
5936 + ctx->current->context_ndx,
5937 + ctx->current->key->ptr, A->ptr);
5939 + } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
5940 array_insert_unique(ctx->current->value, B);
5943 @@ -180,7 +168,12 @@
5944 array *vars = ctx->current->value;
5947 - if (NULL != (du = array_get_element(vars, A->ptr))) {
5948 + if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
5949 + fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
5950 + ctx->current->context_ndx,
5951 + ctx->current->key->ptr, A->ptr);
5953 + } else if (NULL != (du = array_get_element(vars, A->ptr))) {
5954 /* exists in current block */
5955 du = configparser_merge_data(du, B);
5958 buffer_copy_string_buffer(du->key, A);
5959 array_replace(vars, du);
5962 } else if (NULL != (du = configparser_get_variable(ctx, A))) {
5963 du = configparser_merge_data(du, B);
5965 @@ -199,15 +193,13 @@
5966 buffer_copy_string_buffer(du->key, A);
5967 array_insert_unique(ctx->current->value, du);
5971 - fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n",
5972 - ctx->current->context_ndx,
5973 - ctx->current->key->ptr, A->ptr);
5975 + buffer_copy_string_buffer(B->key, A);
5976 + array_insert_unique(ctx->current->value, B);
5984 @@ -239,7 +231,24 @@
5987 value(A) ::= key(B). {
5988 - A = configparser_get_variable(ctx, B);
5989 + if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
5992 + if (NULL != (env = getenv(B->ptr + 4))) {
5994 + ds = data_string_init();
5995 + buffer_append_string(ds->value, env);
5996 + A = (data_unset *)ds;
6000 + fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
6003 + } else if (NULL == (A = configparser_get_variable(ctx, B))) {
6004 + fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
6008 /* make a dummy so it won't crash */
6009 A = (data_unset *)data_string_init();
6011 ((data_array *)(A))->value = B;
6014 +array(A) ::= LPARAN RPARAN. {
6017 array(A) ::= LPARAN aelements(B) RPARAN. {
6020 --- ../lighttpd-1.4.11/src/connections-glue.c 2005-09-12 10:04:23.000000000 +0300
6021 +++ lighttpd-1.4.12/src/connections-glue.c 2006-07-16 00:26:03.000000000 +0300
6023 case CON_STATE_REQUEST_END: return "req-end";
6024 case CON_STATE_RESPONSE_START: return "resp-start";
6025 case CON_STATE_RESPONSE_END: return "resp-end";
6026 - default: return "(unknown)";
6027 + default: return "(unknown)";
6032 case CON_STATE_REQUEST_END: return "Q";
6033 case CON_STATE_RESPONSE_START: return "s";
6034 case CON_STATE_RESPONSE_END: return "S";
6035 - default: return "x";
6036 + default: return "x";
6040 int connection_set_state(server *srv, connection *con, connection_state_t state) {
6050 --- ../lighttpd-1.4.11/src/connections.c 2006-03-05 22:14:53.000000000 +0200
6051 +++ lighttpd-1.4.12/src/connections.c 2006-07-18 13:03:40.000000000 +0300
6056 -#include <unistd.h>
6061 #include "inet_ntop_cache.h"
6064 -# include <openssl/ssl.h>
6065 -# include <openssl/err.h>
6066 +# include <openssl/ssl.h>
6067 +# include <openssl/err.h>
6070 #ifdef HAVE_SYS_FILIO_H
6074 #include "sys-socket.h"
6075 +#include "sys-files.h"
6082 static connection *connections_get_new_connection(server *srv) {
6083 connections *conns = srv->conns;
6087 if (conns->size == 0) {
6091 } else if (conns->size == conns->used) {
6093 conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size);
6096 for (i = conns->used; i < conns->size; i++) {
6097 conns->ptr[i] = connection_init(srv);
6101 connection_reset(srv, conns->ptr[conns->used]);
6103 - fprintf(stderr, "%s.%d: add: ", __FILE__, __LINE__);
6104 - for (i = 0; i < conns->used + 1; i++) {
6105 - fprintf(stderr, "%d ", conns->ptr[i]->fd);
6107 - fprintf(stderr, "\n");
6111 conns->ptr[conns->used]->ndx = conns->used;
6112 return conns->ptr[conns->used++];
6114 @@ -77,263 +70,134 @@
6116 connections *conns = srv->conns;
6120 if (con == NULL) return -1;
6123 if (-1 == con->ndx) return -1;
6129 /* not last element */
6132 if (i != conns->used - 1) {
6133 temp = conns->ptr[i];
6134 conns->ptr[i] = conns->ptr[conns->used - 1];
6135 conns->ptr[conns->used - 1] = temp;
6138 conns->ptr[i]->ndx = i;
6139 conns->ptr[conns->used - 1]->ndx = -1;
6148 - fprintf(stderr, "%s.%d: del: (%d)", __FILE__, __LINE__, conns->used);
6149 - for (i = 0; i < conns->used; i++) {
6150 - fprintf(stderr, "%d ", conns->ptr[i]->fd);
6152 - fprintf(stderr, "\n");
6158 int connection_close(server *srv, connection *con) {
6160 server_socket *srv_sock = con->srv_socket;
6165 if (srv_sock->is_ssl) {
6166 - if (con->ssl) SSL_free(con->ssl);
6168 + if (con->sock->ssl) SSL_free(con->sock->ssl);
6169 + con->sock->ssl = NULL;
6173 - fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
6174 - fdevent_unregister(srv->ev, con->fd);
6176 - if (closesocket(con->fd)) {
6177 - log_error_write(srv, __FILE__, __LINE__, "sds",
6178 - "(warning) close:", con->fd, strerror(errno));
6181 - if (close(con->fd)) {
6183 + fdevent_event_del(srv->ev, con->sock);
6184 + fdevent_unregister(srv->ev, con->sock);
6186 + if (closesocket(con->sock->fd)) {
6187 log_error_write(srv, __FILE__, __LINE__, "sds",
6188 - "(warning) close:", con->fd, strerror(errno));
6189 + "(warning) close:", con->sock->fd, strerror(errno));
6196 - log_error_write(srv, __FILE__, __LINE__, "sd",
6197 - "closed()", con->fd);
6201 connection_del(srv, con);
6202 connection_set_state(srv, con, CON_STATE_CONNECT);
6209 static void dump_packet(const unsigned char *data, size_t len) {
6213 if (len == 0) return;
6216 for (i = 0; i < len; i++) {
6217 if (i % 16 == 0) fprintf(stderr, " ");
6220 fprintf(stderr, "%02x ", data[i]);
6223 if ((i + 1) % 16 == 0) {
6224 fprintf(stderr, " ");
6225 for (j = 0; j <= i % 16; j++) {
6229 if (i-15+j >= len) break;
6235 fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6239 fprintf(stderr, "\n");
6244 if (len % 16 != 0) {
6245 for (j = i % 16; j < 16; j++) {
6246 fprintf(stderr, " ");
6250 fprintf(stderr, " ");
6251 for (j = i & ~0xf; j < len; j++) {
6256 fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6258 fprintf(stderr, "\n");
6263 -static int connection_handle_read(server *srv, connection *con) {
6268 - server_socket *srv_sock = con->srv_socket;
6271 - b = chunkqueue_get_append_buffer(con->read_queue);
6272 - buffer_prepare_copy(b, 4096);
6275 - if (srv_sock->is_ssl) {
6276 - len = SSL_read(con->ssl, b->ptr, b->size - 1);
6278 - if (ioctl(con->fd, FIONREAD, &toread)) {
6279 - log_error_write(srv, __FILE__, __LINE__, "sd",
6280 - "unexpected end-of-file:",
6284 - buffer_prepare_copy(b, toread);
6285 +static network_status_t connection_handle_read(server *srv, connection *con) {
6286 + off_t oldlen, newlen;
6288 - len = read(con->fd, b->ptr, b->size - 1);
6290 -#elif defined(__WIN32)
6291 - len = recv(con->fd, b->ptr, b->size - 1, 0);
6293 - if (ioctl(con->fd, FIONREAD, &toread)) {
6294 - log_error_write(srv, __FILE__, __LINE__, "sd",
6295 - "unexpected end-of-file:",
6299 - buffer_prepare_copy(b, toread);
6300 + oldlen = chunkqueue_length(con->read_queue);
6302 - len = read(con->fd, b->ptr, b->size - 1);
6306 + switch(network_read_chunkqueue(srv, con, con->read_queue)) {
6307 + case NETWORK_STATUS_SUCCESS:
6309 + case NETWORK_STATUS_WAIT_FOR_EVENT:
6310 + con->is_readable = 0;
6311 + return NETWORK_STATUS_WAIT_FOR_EVENT;
6312 + case NETWORK_STATUS_INTERRUPTED:
6313 + con->is_readable = 1;
6314 + return NETWORK_STATUS_WAIT_FOR_EVENT;
6315 + case NETWORK_STATUS_CONNECTION_CLOSE:
6317 + con->is_readable = 0;
6318 + return NETWORK_STATUS_CONNECTION_CLOSE;
6319 + case NETWORK_STATUS_FATAL_ERROR:
6320 con->is_readable = 0;
6323 - if (srv_sock->is_ssl) {
6326 - switch ((r = SSL_get_error(con->ssl, len))) {
6327 - case SSL_ERROR_WANT_READ:
6329 - case SSL_ERROR_SYSCALL:
6331 - * man SSL_get_error()
6333 - * SSL_ERROR_SYSCALL
6334 - * Some I/O error occurred. The OpenSSL error queue may contain more
6335 - * information on the error. If the error queue is empty (i.e.
6336 - * ERR_get_error() returns 0), ret can be used to find out more about
6337 - * the error: If ret == 0, an EOF was observed that violates the
6338 - * protocol. If ret == -1, the underlying BIO reported an I/O error
6339 - * (for socket I/O on Unix systems, consult errno for details).
6342 - while((ssl_err = ERR_get_error())) {
6343 - /* get all errors from the error-queue */
6344 - log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
6345 - r, ERR_error_string(ssl_err, NULL));
6350 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
6357 - case SSL_ERROR_ZERO_RETURN:
6358 - /* clean shutdown on the remote side */
6361 - /* FIXME: later */
6364 - /* fall thourgh */
6366 - while((ssl_err = ERR_get_error())) {
6367 - /* get all errors from the error-queue */
6368 - log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
6369 - r, ERR_error_string(ssl_err, NULL));
6374 - if (errno == EAGAIN) return 0;
6375 - if (errno == EINTR) {
6376 - /* we have been interrupted before we could read */
6377 - con->is_readable = 1;
6381 - if (errno != ECONNRESET) {
6382 - /* expected for keep-alive */
6383 - log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6387 - if (errno == EAGAIN) return 0;
6388 - if (errno == EINTR) {
6389 - /* we have been interrupted before we could read */
6390 - con->is_readable = 1;
6394 - if (errno != ECONNRESET) {
6395 - /* expected for keep-alive */
6396 - log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6399 connection_set_state(srv, con, CON_STATE_ERROR);
6402 - } else if (len == 0) {
6403 - con->is_readable = 0;
6404 - /* the other end close the connection -> KEEP-ALIVE */
6405 + return NETWORK_STATUS_FATAL_ERROR;
6412 + newlen = chunkqueue_length(con->read_queue);
6415 - } else if ((size_t)len < b->size - 1) {
6416 - /* we got less then expected, wait for the next fd-event */
6418 - con->is_readable = 0;
6422 - b->ptr[b->used++] = '\0';
6424 - con->bytes_read += len;
6426 - dump_packet(b->ptr, len);
6430 + con->bytes_read += (newlen - oldlen);
6432 + return NETWORK_STATUS_SUCCESS;
6435 static int connection_handle_write_prepare(server *srv, connection *con) {
6437 case HTTP_METHOD_GET:
6438 case HTTP_METHOD_POST:
6439 case HTTP_METHOD_HEAD:
6441 case HTTP_METHOD_PUT:
6442 case HTTP_METHOD_MKCOL:
6443 case HTTP_METHOD_DELETE:
6444 @@ -350,12 +215,14 @@
6445 case HTTP_METHOD_MOVE:
6446 case HTTP_METHOD_PROPFIND:
6447 case HTTP_METHOD_PROPPATCH:
6448 + case HTTP_METHOD_LOCK:
6449 + case HTTP_METHOD_UNLOCK:
6451 case HTTP_METHOD_OPTIONS:
6453 * 400 is coming from the request-parser BEFORE uri.path is set
6454 - * 403 is from the response handler when noone else catched it
6456 + * 403 is from the response handler when noone else catched it
6459 if (con->uri.path->used &&
6460 con->uri.path->ptr[0] != '*') {
6461 @@ -381,55 +248,60 @@
6467 if (con->http_status == 0) {
6468 con->http_status = 403;
6472 switch(con->http_status) {
6473 case 400: /* class: header + custom body */
6491 if (con->mode != DIRECT) break;
6494 con->file_finished = 0;
6497 buffer_reset(con->physical.path);
6500 /* try to send static errorfile */
6501 if (!buffer_is_empty(con->conf.errorfile_prefix)) {
6502 stat_cache_entry *sce = NULL;
6505 buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix);
6506 buffer_append_string(con->physical.path, get_http_status_body_name(con->http_status));
6509 if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
6510 con->file_finished = 1;
6513 http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
6514 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
6518 - if (!con->file_finished) {
6520 + if (!con->file_finished) {
6524 buffer_reset(con->physical.path);
6527 con->file_finished = 1;
6528 b = chunkqueue_get_append_buffer(con->write_queue);
6531 /* build default error-page */
6532 - buffer_copy_string(b,
6533 + buffer_copy_string(b,
6534 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
6535 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
6536 " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
6538 buffer_append_long(b, con->http_status);
6539 buffer_append_string(b, " - ");
6540 buffer_append_string(b, get_http_status_name(con->http_status));
6543 buffer_append_string(b,
6546 @@ -448,12 +320,12 @@
6547 buffer_append_long(b, con->http_status);
6548 buffer_append_string(b, " - ");
6549 buffer_append_string(b, get_http_status_name(con->http_status));
6551 - buffer_append_string(b,"</h1>\n"
6553 + buffer_append_string(b,"</h1>\n"
6559 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
6562 @@ -463,10 +335,10 @@
6568 case 206: /* write_queue is already prepared */
6569 con->file_finished = 1;
6573 case 205: /* class: header only */
6575 @@ -474,19 +346,19 @@
6576 /* disable chunked encoding again as we have no body */
6577 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
6578 chunkqueue_reset(con->write_queue);
6581 con->file_finished = 1;
6587 if (con->file_finished) {
6588 - /* we have all the content and chunked encoding is not used, set a content-length */
6590 - if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) &&
6591 + /* we have all the content and chunked encoding is not used, set a content-length */
6593 + if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) &&
6594 (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) {
6595 buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->write_queue));
6598 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
6601 @@ -495,77 +367,79 @@
6602 ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) {
6603 con->keep_alive = 0;
6607 if (0 == (con->parsed_response & HTTP_CONNECTION)) {
6608 /* (f)cgi did'nt send Connection: header
6613 if (((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) &&
6614 (con->parsed_response & HTTP_CONTENT_LENGTH) == 0) {
6615 /* without content_length, no keep-alive */
6618 con->keep_alive = 0;
6621 /* a subrequest disable keep-alive although the client wanted it */
6622 if (con->keep_alive && !con->response.keep_alive) {
6623 con->keep_alive = 0;
6626 /* FIXME: we have to drop the Connection: Header from the subrequest */
6632 if (con->request.http_method == HTTP_METHOD_HEAD) {
6633 chunkqueue_reset(con->write_queue);
6636 http_response_write_header(srv, con);
6642 static int connection_handle_write(server *srv, connection *con) {
6643 switch(network_write_chunkqueue(srv, con, con->write_queue)) {
6645 + case NETWORK_STATUS_SUCCESS:
6646 if (con->file_finished) {
6647 connection_set_state(srv, con, CON_STATE_RESPONSE_END);
6648 joblist_append(srv, con);
6651 - case -1: /* error on our side */
6652 + case NETWORK_STATUS_FATAL_ERROR: /* error on our side */
6653 log_error_write(srv, __FILE__, __LINE__, "sd",
6654 - "connection closed: write failed on fd", con->fd);
6655 + "connection closed: write failed on fd", con->sock->fd);
6656 connection_set_state(srv, con, CON_STATE_ERROR);
6657 joblist_append(srv, con);
6659 - case -2: /* remote close */
6660 + case NETWORK_STATUS_CONNECTION_CLOSE: /* remote close */
6661 connection_set_state(srv, con, CON_STATE_ERROR);
6662 joblist_append(srv, con);
6665 + case NETWORK_STATUS_WAIT_FOR_EVENT:
6666 con->is_writable = 0;
6669 /* not finished yet -> WRITE */
6671 + case NETWORK_STATUS_INTERRUPTED:
6672 + con->is_writable = 1;
6674 + case NETWORK_STATUS_UNSET:
6684 connection *connection_init(server *srv) {
6690 con = calloc(1, sizeof(*con));
6694 + con->sock = iosocket_init();
6696 - con->fde_ndx = -1;
6697 con->bytes_written = 0;
6698 con->bytes_read = 0;
6699 con->bytes_header = 0;
6700 @@ -573,32 +447,32 @@
6703 con->x = buffer_init();
6707 CLEAN(request.request_line);
6708 CLEAN(request.request);
6709 CLEAN(request.pathinfo);
6712 CLEAN(request.orig_uri);
6716 CLEAN(uri.authority);
6718 CLEAN(uri.path_raw);
6722 CLEAN(physical.doc_root);
6723 CLEAN(physical.path);
6724 CLEAN(physical.basedir);
6725 CLEAN(physical.rel_path);
6726 CLEAN(physical.etag);
6727 CLEAN(parse_request);
6732 CLEAN(error_handler);
6733 CLEAN(dst_addr_buf);
6737 con->write_queue = chunkqueue_init();
6738 con->read_queue = chunkqueue_init();
6739 @@ -608,26 +482,27 @@
6740 con->request.headers = array_init();
6741 con->response.headers = array_init();
6742 con->environment = array_init();
6745 /* init plugin specific connection structures */
6748 con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
6751 con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
6752 config_setup_connection(srv, con);
6758 void connections_free(server *srv) {
6759 connections *conns = srv->conns;
6764 for (i = 0; i < conns->size; i++) {
6765 connection *con = conns->ptr[i];
6768 connection_reset(srv, con);
6770 + iosocket_free(con->sock);
6772 chunkqueue_free(con->write_queue);
6773 chunkqueue_free(con->read_queue);
6774 chunkqueue_free(con->request_content_queue);
6775 @@ -637,27 +512,27 @@
6778 buffer_free(con->x);
6782 CLEAN(request.request_line);
6783 CLEAN(request.request);
6784 CLEAN(request.pathinfo);
6787 CLEAN(request.orig_uri);
6791 CLEAN(uri.authority);
6793 CLEAN(uri.path_raw);
6797 CLEAN(physical.doc_root);
6798 CLEAN(physical.path);
6799 CLEAN(physical.basedir);
6800 CLEAN(physical.etag);
6801 CLEAN(physical.rel_path);
6802 CLEAN(parse_request);
6807 CLEAN(error_handler);
6808 @@ -665,97 +540,97 @@
6810 free(con->plugin_ctx);
6811 free(con->cond_cache);
6822 int connection_reset(server *srv, connection *con) {
6826 plugins_call_connection_reset(srv, con);
6829 con->is_readable = 1;
6830 con->is_writable = 1;
6831 con->http_status = 0;
6832 con->file_finished = 0;
6833 con->file_started = 0;
6834 con->got_response = 0;
6837 con->parsed_response = 0;
6840 con->bytes_written = 0;
6841 con->bytes_written_cur_second = 0;
6842 con->bytes_read = 0;
6843 con->bytes_header = 0;
6844 con->loops_per_request = 0;
6847 con->request.http_method = HTTP_METHOD_UNSET;
6848 con->request.http_version = HTTP_VERSION_UNSET;
6851 con->request.http_if_modified_since = NULL;
6852 con->request.http_if_none_match = NULL;
6855 con->response.keep_alive = 0;
6856 con->response.content_length = -1;
6857 con->response.transfer_encoding = 0;
6864 if (con->x) buffer_reset(con->x);
6868 CLEAN(request.request_line);
6869 CLEAN(request.pathinfo);
6870 CLEAN(request.request);
6873 CLEAN(request.orig_uri);
6877 CLEAN(uri.authority);
6879 CLEAN(uri.path_raw);
6883 CLEAN(physical.doc_root);
6884 CLEAN(physical.path);
6885 CLEAN(physical.basedir);
6886 CLEAN(physical.rel_path);
6887 CLEAN(physical.etag);
6890 CLEAN(parse_request);
6895 CLEAN(error_handler);
6901 - if (con->x) con->x->used = 0;
6903 + if (con->x) con->x->used = 0;
6909 con->request.x = NULL;
6914 CLEAN(http_content_type);
6916 con->request.content_length = 0;
6919 array_reset(con->request.headers);
6920 array_reset(con->response.headers);
6921 array_reset(con->environment);
6924 chunkqueue_reset(con->write_queue);
6925 chunkqueue_reset(con->request_content_queue);
6927 - /* the plugins should cleanup themself */
6928 + /* the plugins should cleanup themself */
6929 for (i = 0; i < srv->plugins.used; i++) {
6930 plugin *p = ((plugin **)(srv->plugins.ptr))[i];
6931 plugin_data *pd = p->data;
6934 con->plugin_ctx[pd->id] = NULL;
6938 #if COND_RESULT_UNSET
6939 for (i = srv->config_context->used - 1; i >= 0; i --) {
6940 con->cond_cache[i].result = COND_RESULT_UNSET;
6941 @@ -777,56 +652,56 @@
6943 memset(con->cond_cache, 0, sizeof(cond_cache_t) * srv->config_context->used);
6947 con->header_len = 0;
6948 con->in_error_handler = 0;
6951 config_setup_connection(srv, con);
6959 - * search for \r\n\r\n
6962 + * search for \r\n\r\n
6964 * this is a special 32bit version which is using a sliding window for
6965 - * the comparisions
6967 + * the comparisions
6976 * cmpbuf: abcd != cdef
6977 * cmpbuf: bcde != cdef
6978 * cmpbuf: cdef == cdef -> return &c
6980 - * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to
6982 + * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to
6983 * maintain cmpbuf and rnrn
6988 char *buffer_search_rnrn(buffer *b) {
6989 uint32_t cmpbuf, rnrn;
6994 if (b->used < 4) return NULL;
6997 rnrn = ('\r' << 24) | ('\n' << 16) |
6998 ('\r' << 8) | ('\n' << 0);
7001 cmpbuf = (b->ptr[0] << 24) | (b->ptr[1] << 16) |
7002 (b->ptr[2] << 8) | (b->ptr[3] << 0);
7006 for (i = 0; i < b->used - 4; i++) {
7007 if (cmpbuf == rnrn) return cp - 4;
7010 cmpbuf = (cmpbuf << 8 | *(cp++)) & 0xffffffff;
7017 @@ -840,22 +715,25 @@
7019 chunkqueue *cq = con->read_queue;
7020 chunkqueue *dst_cq = con->request_content_queue;
7023 if (con->is_readable) {
7024 con->read_idle_ts = srv->cur_ts;
7027 switch(connection_handle_read(srv, con)) {
7029 + case NETWORK_STATUS_FATAL_ERROR:
7032 + case NETWORK_STATUS_CONNECTION_CLOSE:
7033 /* remote side closed the connection
7034 * if we still have content, handle it, if not leave here */
7036 if (cq->first == cq->last &&
7037 - cq->first->mem->used == 0) {
7038 + (NULL == cq->first ||
7039 + cq->first->mem->used == 0)) {
7041 /* conn-closed, leave here */
7042 connection_set_state(srv, con, CON_STATE_ERROR);
7048 @@ -891,14 +769,14 @@
7049 /* the last node was empty */
7050 if (c->next == NULL) {
7062 /* nothing to handle */
7063 if (cq->first == NULL) return 0;
7065 @@ -906,25 +784,26 @@
7066 case CON_STATE_READ:
7067 /* prepare con->request.request */
7071 /* check if we need the full package */
7072 if (con->request.request->used == 0) {
7076 b.ptr = c->mem->ptr + c->offset;
7077 b.used = c->mem->used - c->offset;
7080 if (NULL != (h_term = buffer_search_rnrn(&b))) {
7082 * - copy everything incl. the terminator to request.request
7085 - buffer_copy_string_len(con->request.request,
7088 + buffer_copy_string_len(con->request.request,
7090 h_term - b.ptr + 4);
7093 /* the buffer has been read up to the terminator */
7094 c->offset += h_term - b.ptr + 4;
7097 /* not found, copy everything */
7098 buffer_copy_string_len(con->request.request, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
7099 @@ -932,14 +811,14 @@
7102 /* have to take care of overlapping header terminators */
7105 size_t l = con->request.request->used - 2;
7106 char *s = con->request.request->ptr;
7110 b.ptr = c->mem->ptr + c->offset;
7111 b.used = c->mem->used - c->offset;
7114 if (con->request.request->used - 1 > 3 &&
7118 c->mem->ptr[0] == '\n') {
7119 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 1);
7123 h_term = con->request.request->ptr;
7124 } else if (con->request.request->used - 1 > 2 &&
7127 c->mem->ptr[1] == '\n') {
7128 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 2);
7132 h_term = con->request.request->ptr;
7133 } else if (con->request.request->used - 1 > 1 &&
7135 @@ -968,17 +847,17 @@
7136 c->mem->ptr[2] == '\n') {
7137 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 3);
7141 h_term = con->request.request->ptr;
7142 } else if (NULL != (h_term = buffer_search_string_len(&b, "\r\n\r\n", 4))) {
7144 * - copy everything incl. the terminator to request.request
7147 - buffer_append_string_len(con->request.request,
7148 - c->mem->ptr + c->offset,
7150 + buffer_append_string_len(con->request.request,
7151 + c->mem->ptr + c->offset,
7152 c->offset + h_term - b.ptr + 4);
7155 /* the buffer has been read up to the terminator */
7156 c->offset += h_term - b.ptr + 4;
7158 @@ -999,16 +878,16 @@
7159 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7162 - case CON_STATE_READ_POST:
7163 + case CON_STATE_READ_POST:
7164 for (c = cq->first; c && (dst_cq->bytes_in != (off_t)con->request.content_length); c = c->next) {
7165 off_t weWant, weHave, toRead;
7168 weWant = con->request.content_length - dst_cq->bytes_in;
7171 assert(c->mem->used);
7174 weHave = c->mem->used - c->offset - 1;
7177 toRead = weHave > weWant ? weWant : weHave;
7179 /* the new way, copy everything into a chunkqueue whcih might use tempfiles */
7180 @@ -1017,13 +896,13 @@
7181 /* copy everything to max 1Mb sized tempfiles */
7184 - * if the last chunk is
7185 + * if the last chunk is
7186 * - smaller than 1Mb (size < 1Mb)
7187 * - not read yet (offset == 0)
7190 - * -> create a new chunk
7192 + * -> create a new chunk
7197 @@ -1056,14 +935,14 @@
7198 /* we have a chunk, let's write to it */
7200 if (dst_c->file.fd == -1) {
7201 - /* we don't have file to write to,
7202 + /* we don't have file to write to,
7203 * EACCES might be one reason.
7205 * Instead of sending 500 we send 413 and say the request is too large
7208 log_error_write(srv, __FILE__, __LINE__, "sbs",
7209 - "denying upload as opening to temp-file for upload failed:",
7210 + "denying upload as opening to temp-file for upload failed:",
7211 dst_c->file.name, strerror(errno));
7213 con->http_status = 413; /* Request-Entity too large */
7214 @@ -1074,15 +953,15 @@
7217 if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) {
7218 - /* write failed for some reason ... disk full ? */
7219 + /* write failed for some reason ... disk full ? */
7220 log_error_write(srv, __FILE__, __LINE__, "sbs",
7221 - "denying upload as writing to file failed:",
7222 + "denying upload as writing to file failed:",
7223 dst_c->file.name, strerror(errno));
7226 con->http_status = 413; /* Request-Entity too large */
7227 con->keep_alive = 0;
7228 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7231 close(dst_c->file.fd);
7232 dst_c->file.fd = -1;
7234 @@ -1090,7 +969,7 @@
7237 dst_c->file.length += toRead;
7240 if (dst_cq->bytes_in + toRead == (off_t)con->request.content_length) {
7241 /* we read everything, close the chunk */
7242 close(dst_c->file.fd);
7243 @@ -1102,7 +981,7 @@
7244 b = chunkqueue_get_append_buffer(dst_cq);
7245 buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead);
7249 c->offset += toRead;
7250 dst_cq->bytes_in += toRead;
7252 @@ -1111,7 +990,7 @@
7253 if (dst_cq->bytes_in == (off_t)con->request.content_length) {
7254 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7261 @@ -1123,100 +1002,104 @@
7262 handler_t connection_handle_fdevent(void *s, void *context, int revents) {
7263 server *srv = (server *)s;
7264 connection *con = context;
7267 joblist_append(srv, con);
7270 if (revents & FDEVENT_IN) {
7271 con->is_readable = 1;
7273 - log_error_write(srv, __FILE__, __LINE__, "sd", "read-wait - done", con->fd);
7276 if (revents & FDEVENT_OUT) {
7277 con->is_writable = 1;
7278 /* we don't need the event twice */
7284 if (revents & ~(FDEVENT_IN | FDEVENT_OUT)) {
7285 /* looks like an error */
7288 /* FIXME: revents = 0x19 still means that we should read from the queue */
7289 if (revents & FDEVENT_HUP) {
7290 if (con->state == CON_STATE_CLOSE) {
7291 con->close_timeout_ts = 0;
7293 /* sigio reports the wrong event here
7295 - * there was no HUP at all
7297 + * there was no HUP at all
7299 #ifdef USE_LINUX_SIGIO
7300 if (srv->ev->in_sigio == 1) {
7301 log_error_write(srv, __FILE__, __LINE__, "sd",
7302 - "connection closed: poll() -> HUP", con->fd);
7303 + "connection closed: poll() -> HUP", con->sock->fd);
7305 connection_set_state(srv, con, CON_STATE_ERROR);
7308 connection_set_state(srv, con, CON_STATE_ERROR);
7313 } else if (revents & FDEVENT_ERR) {
7314 #ifndef USE_LINUX_SIGIO
7315 log_error_write(srv, __FILE__, __LINE__, "sd",
7316 - "connection closed: poll() -> ERR", con->fd);
7318 + "connection closed: poll() -> ERR", con->sock->fd);
7320 connection_set_state(srv, con, CON_STATE_ERROR);
7322 log_error_write(srv, __FILE__, __LINE__, "sd",
7323 "connection closed: poll() -> ???", revents);
7329 if (con->state == CON_STATE_READ ||
7330 con->state == CON_STATE_READ_POST) {
7331 connection_handle_read_state(srv, con);
7333 + * if SSL_read() is not readin in the full packet we won't get
7334 + * a fdevent as the low-level has already fetched everything.
7336 + * we have to call the state-engine to read the rest of the packet
7338 + if (con->is_readable) joblist_append(srv, con);
7342 if (con->state == CON_STATE_WRITE &&
7343 !chunkqueue_is_empty(con->write_queue) &&
7347 if (-1 == connection_handle_write(srv, con)) {
7348 connection_set_state(srv, con, CON_STATE_ERROR);
7351 log_error_write(srv, __FILE__, __LINE__, "ds",
7354 "handle write failed.");
7355 } else if (con->state == CON_STATE_WRITE) {
7356 con->write_request_ts = srv->cur_ts;
7361 if (con->state == CON_STATE_CLOSE) {
7362 /* flush the read buffers */
7365 - if (ioctl(con->fd, FIONREAD, &b)) {
7367 + if (ioctl(con->sock->fd, FIONREAD, &b)) {
7368 log_error_write(srv, __FILE__, __LINE__, "ss",
7369 "ioctl() failed", strerror(errno));
7375 log_error_write(srv, __FILE__, __LINE__, "sdd",
7376 - "CLOSE-read()", con->fd, b);
7378 + "CLOSE-read()", con->sock->fd, b);
7381 - read(con->fd, buf, sizeof(buf));
7382 + read(con->sock->fd, buf, sizeof(buf));
7384 /* nothing to read */
7387 con->close_timeout_ts = 0;
7392 return HANDLER_FINISHED;
7395 @@ -1229,63 +1112,68 @@
7398 /* accept it and register the fd */
7401 cnt_len = sizeof(cnt_addr);
7403 - if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7404 + if (-1 == (cnt = accept(srv_socket->sock->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7406 + errno = WSAGetLastError();
7408 if ((errno != EAGAIN) &&
7409 + (errno != EWOULDBLOCK) &&
7411 - log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno);
7412 + log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), srv_socket->sock->fd);
7422 /* ok, we have the connection, register it */
7424 log_error_write(srv, __FILE__, __LINE__, "sd",
7430 con = connections_get_new_connection(srv);
7433 - con->fde_ndx = -1;
7435 + con->sock->fd = cnt;
7436 + con->sock->fde_ndx = -1;
7438 gettimeofday(&(con->start_tv), NULL);
7440 - fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con);
7443 + fdevent_register(srv->ev, con->sock, connection_handle_fdevent, con);
7445 connection_set_state(srv, con, CON_STATE_REQUEST_START);
7448 con->connection_start = srv->cur_ts;
7449 con->dst_addr = cnt_addr;
7450 buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
7451 con->srv_socket = srv_socket;
7453 - if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) {
7455 + if (-1 == (fdevent_fcntl_set(srv->ev, con->sock))) {
7456 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
7457 + connection_close(srv, con);
7461 /* connect FD to SSL */
7462 if (srv_socket->is_ssl) {
7463 - if (NULL == (con->ssl = SSL_new(srv_socket->ssl_ctx))) {
7464 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7465 + if (NULL == (con->sock->ssl = SSL_new(srv_socket->ssl_ctx))) {
7466 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7467 ERR_error_string(ERR_get_error(), NULL));
7469 + connection_close(srv, con);
7473 - SSL_set_accept_state(con->ssl);
7475 + SSL_set_accept_state(con->sock->ssl);
7478 - if (1 != (SSL_set_fd(con->ssl, cnt))) {
7479 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7481 + if (1 != (SSL_set_fd(con->sock->ssl, cnt))) {
7482 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7483 ERR_error_string(ERR_get_error(), NULL));
7484 + connection_close(srv, con);
7488 @@ -1300,102 +1188,102 @@
7490 server_socket *srv_sock = con->srv_socket;
7494 if (srv->srvconf.log_state_handling) {
7495 - log_error_write(srv, __FILE__, __LINE__, "sds",
7498 + log_error_write(srv, __FILE__, __LINE__, "sds",
7501 connection_get_state(con->state));
7505 size_t ostate = con->state;
7509 switch (con->state) {
7510 case CON_STATE_REQUEST_START: /* transient */
7511 if (srv->srvconf.log_state_handling) {
7512 - log_error_write(srv, __FILE__, __LINE__, "sds",
7513 - "state for fd", con->fd, connection_get_state(con->state));
7514 + log_error_write(srv, __FILE__, __LINE__, "sds",
7515 + "state for fd", con->sock->fd, connection_get_state(con->state));
7519 con->request_start = srv->cur_ts;
7520 con->read_idle_ts = srv->cur_ts;
7523 con->request_count++;
7524 con->loops_per_request = 0;
7527 connection_set_state(srv, con, CON_STATE_READ);
7531 case CON_STATE_REQUEST_END: /* transient */
7532 if (srv->srvconf.log_state_handling) {
7533 - log_error_write(srv, __FILE__, __LINE__, "sds",
7534 - "state for fd", con->fd, connection_get_state(con->state));
7535 + log_error_write(srv, __FILE__, __LINE__, "sds",
7536 + "state for fd", con->sock->fd, connection_get_state(con->state));
7540 if (http_request_parse(srv, con)) {
7541 /* we have to read some data from the POST request */
7544 connection_set_state(srv, con, CON_STATE_READ_POST);
7550 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7554 case CON_STATE_HANDLE_REQUEST:
7557 * the request is parsed
7560 * decided what to do with the request
7570 if (srv->srvconf.log_state_handling) {
7571 - log_error_write(srv, __FILE__, __LINE__, "sds",
7572 - "state for fd", con->fd, connection_get_state(con->state));
7573 + log_error_write(srv, __FILE__, __LINE__, "sds",
7574 + "state for fd", con->sock->fd, connection_get_state(con->state));
7578 switch (r = http_response_prepare(srv, con)) {
7579 case HANDLER_FINISHED:
7580 if (con->http_status == 404 ||
7581 con->http_status == 403) {
7582 /* 404 error-handler */
7584 - if (con->in_error_handler == 0 &&
7586 + if (con->in_error_handler == 0 &&
7587 (!buffer_is_empty(con->conf.error_handler) ||
7588 !buffer_is_empty(con->error_handler))) {
7589 /* call error-handler */
7592 con->error_handler_saved_status = con->http_status;
7593 con->http_status = 0;
7596 if (buffer_is_empty(con->error_handler)) {
7597 buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
7599 buffer_copy_string_buffer(con->request.uri, con->error_handler);
7601 buffer_reset(con->physical.path);
7604 con->in_error_handler = 1;
7607 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7612 } else if (con->in_error_handler) {
7613 /* error-handler is a 404 */
7616 /* continue as normal, status is the same */
7617 - log_error_write(srv, __FILE__, __LINE__, "sb",
7618 + log_error_write(srv, __FILE__, __LINE__, "sb",
7619 "Warning: Either the error-handler returned status 404 or the error-handler itself was not found:", con->request.uri);
7620 - log_error_write(srv, __FILE__, __LINE__, "sd",
7621 + log_error_write(srv, __FILE__, __LINE__, "sd",
7622 "returning the original status", con->error_handler_saved_status);
7623 - log_error_write(srv, __FILE__, __LINE__, "s",
7624 + log_error_write(srv, __FILE__, __LINE__, "s",
7625 "If this is a rails app: check your production.log");
7626 con->http_status = con->error_handler_saved_status;
7628 @@ -1403,73 +1291,73 @@
7629 /* error-handler is back and has generated content */
7630 /* if Status: was set, take it otherwise use 200 */
7634 if (con->http_status == 0) con->http_status = 200;
7637 /* we have something to send, go on */
7638 connection_set_state(srv, con, CON_STATE_RESPONSE_START);
7640 case HANDLER_WAIT_FOR_FD:
7644 fdwaitqueue_append(srv, con);
7647 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7651 case HANDLER_COMEBACK:
7653 case HANDLER_WAIT_FOR_EVENT:
7654 /* come back here */
7655 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7660 /* something went wrong */
7661 connection_set_state(srv, con, CON_STATE_ERROR);
7664 - log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r);
7665 + log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->sock->fd, r);
7671 case CON_STATE_RESPONSE_START:
7674 * the decision is done
7675 * - create the HTTP-Response-Header
7681 if (srv->srvconf.log_state_handling) {
7682 - log_error_write(srv, __FILE__, __LINE__, "sds",
7683 - "state for fd", con->fd, connection_get_state(con->state));
7684 + log_error_write(srv, __FILE__, __LINE__, "sds",
7685 + "state for fd", con->sock->fd, connection_get_state(con->state));
7689 if (-1 == connection_handle_write_prepare(srv, con)) {
7690 connection_set_state(srv, con, CON_STATE_ERROR);
7697 connection_set_state(srv, con, CON_STATE_WRITE);
7699 case CON_STATE_RESPONSE_END: /* transient */
7700 /* log the request */
7703 if (srv->srvconf.log_state_handling) {
7704 - log_error_write(srv, __FILE__, __LINE__, "sds",
7705 - "state for fd", con->fd, connection_get_state(con->state));
7706 + log_error_write(srv, __FILE__, __LINE__, "sds",
7707 + "state for fd", con->sock->fd, connection_get_state(con->state));
7711 plugins_call_handle_request_done(srv, con);
7717 if (con->keep_alive) {
7718 connection_set_state(srv, con, CON_STATE_REQUEST_START);
7723 con->request_start = srv->cur_ts;
7724 con->read_idle_ts = srv->cur_ts;
7726 @@ -1482,103 +1370,103 @@
7727 log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r);
7733 if (srv_sock->is_ssl) {
7734 - switch (SSL_shutdown(con->ssl)) {
7735 + switch (SSL_shutdown(con->sock->ssl)) {
7740 - /* wait for fd-event
7742 + /* wait for fd-event
7744 * FIXME: wait for fdevent and call SSL_shutdown again
7752 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7753 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7754 ERR_error_string(ERR_get_error(), NULL));
7758 connection_close(srv, con);
7765 connection_reset(srv, con);
7769 case CON_STATE_CONNECT:
7770 if (srv->srvconf.log_state_handling) {
7771 - log_error_write(srv, __FILE__, __LINE__, "sds",
7772 - "state for fd", con->fd, connection_get_state(con->state));
7773 + log_error_write(srv, __FILE__, __LINE__, "sds",
7774 + "state for fd", con->sock->fd, connection_get_state(con->state));
7778 chunkqueue_reset(con->read_queue);
7781 con->request_count = 0;
7785 case CON_STATE_CLOSE:
7786 if (srv->srvconf.log_state_handling) {
7787 - log_error_write(srv, __FILE__, __LINE__, "sds",
7788 - "state for fd", con->fd, connection_get_state(con->state));
7789 + log_error_write(srv, __FILE__, __LINE__, "sds",
7790 + "state for fd", con->sock->fd, connection_get_state(con->state));
7794 if (con->keep_alive) {
7795 - if (ioctl(con->fd, FIONREAD, &b)) {
7796 + if (ioctl(con->sock->fd, FIONREAD, &b)) {
7797 log_error_write(srv, __FILE__, __LINE__, "ss",
7798 "ioctl() failed", strerror(errno));
7802 log_error_write(srv, __FILE__, __LINE__, "sdd",
7803 - "CLOSE-read()", con->fd, b);
7805 + "CLOSE-read()", con->sock->fd, b);
7808 - read(con->fd, buf, sizeof(buf));
7809 + read(con->sock->fd, buf, sizeof(buf));
7811 /* nothing to read */
7814 con->close_timeout_ts = 0;
7817 con->close_timeout_ts = 0;
7821 if (srv->cur_ts - con->close_timeout_ts > 1) {
7822 connection_close(srv, con);
7825 if (srv->srvconf.log_state_handling) {
7826 - log_error_write(srv, __FILE__, __LINE__, "sd",
7827 - "connection closed for fd", con->fd);
7828 + log_error_write(srv, __FILE__, __LINE__, "sd",
7829 + "connection closed for fd", con->sock->fd);
7835 case CON_STATE_READ_POST:
7836 case CON_STATE_READ:
7837 if (srv->srvconf.log_state_handling) {
7838 - log_error_write(srv, __FILE__, __LINE__, "sds",
7839 - "state for fd", con->fd, connection_get_state(con->state));
7840 + log_error_write(srv, __FILE__, __LINE__, "sds",
7841 + "state for fd", con->sock->fd, connection_get_state(con->state));
7845 connection_handle_read_state(srv, con);
7847 case CON_STATE_WRITE:
7848 if (srv->srvconf.log_state_handling) {
7849 - log_error_write(srv, __FILE__, __LINE__, "sds",
7850 - "state for fd", con->fd, connection_get_state(con->state));
7851 + log_error_write(srv, __FILE__, __LINE__, "sds",
7852 + "state for fd", con->sock->fd, connection_get_state(con->state));
7856 /* only try to write if we have something in the queue */
7857 if (!chunkqueue_is_empty(con->write_queue)) {
7859 log_error_write(srv, __FILE__, __LINE__, "dsd",
7862 "packets to write:",
7863 con->write_queue->used);
7865 @@ -1586,17 +1474,17 @@
7866 if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) {
7867 if (-1 == connection_handle_write(srv, con)) {
7868 log_error_write(srv, __FILE__, __LINE__, "ds",
7871 "handle write failed.");
7872 connection_set_state(srv, con, CON_STATE_ERROR);
7873 } else if (con->state == CON_STATE_WRITE) {
7874 con->write_request_ts = srv->cur_ts;
7880 case CON_STATE_ERROR: /* transient */
7883 /* even if the connection was drop we still have to write it to the access log */
7884 if (con->http_status) {
7885 plugins_call_handle_request_done(srv, con);
7886 @@ -1604,28 +1492,28 @@
7888 if (srv_sock->is_ssl) {
7890 - switch ((ret = SSL_shutdown(con->ssl))) {
7891 + switch ((ret = SSL_shutdown(con->sock->ssl))) {
7896 - SSL_shutdown(con->ssl);
7897 + SSL_shutdown(con->sock->ssl);
7900 - log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
7901 - SSL_get_error(con->ssl, ret),
7902 + log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
7903 + SSL_get_error(con->sock->ssl, ret),
7904 ERR_error_string(ERR_get_error(), NULL));
7914 - log_error_write(srv, __FILE__, __LINE__, "sd",
7915 - "emergency exit: direct",
7917 + log_error_write(srv, __FILE__, __LINE__, "sd",
7918 + "emergency exit: direct",
7923 @@ -1639,35 +1527,35 @@
7929 connection_reset(srv, con);
7932 /* close the connection */
7933 if ((con->keep_alive == 1) &&
7934 - (0 == shutdown(con->fd, SHUT_WR))) {
7935 + (0 == shutdown(con->sock->fd, SHUT_WR))) {
7936 con->close_timeout_ts = srv->cur_ts;
7937 connection_set_state(srv, con, CON_STATE_CLOSE);
7940 if (srv->srvconf.log_state_handling) {
7941 - log_error_write(srv, __FILE__, __LINE__, "sd",
7942 - "shutdown for fd", con->fd);
7943 + log_error_write(srv, __FILE__, __LINE__, "sd",
7944 + "shutdown for fd", con->sock->fd);
7947 connection_close(srv, con);
7951 con->keep_alive = 0;
7959 - log_error_write(srv, __FILE__, __LINE__, "sdd",
7960 - "unknown state:", con->fd, con->state);
7962 + log_error_write(srv, __FILE__, __LINE__, "sdd",
7963 + "unknown state:", con->sock->fd, con->state);
7971 } else if (ostate == con->state) {
7972 @@ -1676,33 +1564,33 @@
7975 if (srv->srvconf.log_state_handling) {
7976 - log_error_write(srv, __FILE__, __LINE__, "sds",
7979 + log_error_write(srv, __FILE__, __LINE__, "sds",
7982 connection_get_state(con->state));
7986 switch(con->state) {
7987 case CON_STATE_READ_POST:
7988 case CON_STATE_READ:
7989 case CON_STATE_CLOSE:
7990 - fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN);
7991 + fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
7993 case CON_STATE_WRITE:
7994 - /* request write-fdevent only if we really need it
7995 + /* request write-fdevent only if we really need it
7996 * - if we have data to write
7997 - * - if the socket is not writable yet
7998 + * - if the socket is not writable yet
8000 - if (!chunkqueue_is_empty(con->write_queue) &&
8001 + if (!chunkqueue_is_empty(con->write_queue) &&
8002 (con->is_writable == 0) &&
8003 (con->traffic_limit_reached == 0)) {
8004 - fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT);
8005 + fdevent_event_add(srv->ev, con->sock, FDEVENT_OUT);
8007 - fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8008 + fdevent_event_del(srv->ev, con->sock);
8012 - fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8013 + fdevent_event_del(srv->ev, con->sock);
8017 --- ../lighttpd-1.4.11/src/crc32.h 2005-09-30 20:18:59.000000000 +0300
8018 +++ lighttpd-1.4.12/src/crc32.h 2006-07-16 00:26:04.000000000 +0300
8022 #include <sys/types.h>
8023 +#include <stdlib.h>
8025 #if defined HAVE_STDINT_H
8028 #include <inttypes.h>
8032 +#define uint32_t unsigned __int32
8035 uint32_t generate_crc32c(char *string, size_t length);
8038 --- ../lighttpd-1.4.11/src/data_array.c 2005-08-23 17:36:12.000000000 +0300
8039 +++ lighttpd-1.4.12/src/data_array.c 2006-07-16 00:26:04.000000000 +0300
8042 static void data_array_free(data_unset *d) {
8043 data_array *ds = (data_array *)d;
8046 buffer_free(ds->key);
8047 array_free(ds->value);
8053 static void data_array_reset(data_unset *d) {
8054 data_array *ds = (data_array *)d;
8057 /* reused array elements */
8058 buffer_reset(ds->key);
8059 array_reset(ds->value);
8071 data_array *data_array_init(void) {
8075 ds = calloc(1, sizeof(*ds));
8078 ds->key = buffer_init();
8079 ds->value = array_init();
8082 ds->copy = data_array_copy;
8083 ds->free = data_array_free;
8084 ds->reset = data_array_reset;
8085 ds->insert_dup = data_array_insert_dup;
8086 ds->print = data_array_print;
8087 ds->type = TYPE_ARRAY;
8092 --- ../lighttpd-1.4.11/src/data_config.c 2005-08-17 12:53:19.000000000 +0300
8093 +++ lighttpd-1.4.12/src/data_config.c 2006-07-16 00:26:03.000000000 +0300
8096 static void data_config_free(data_unset *d) {
8097 data_config *ds = (data_config *)d;
8100 buffer_free(ds->key);
8101 buffer_free(ds->op);
8102 buffer_free(ds->comp_key);
8105 array_free(ds->value);
8106 array_free(ds->childs);
8109 if (ds->string) buffer_free(ds->string);
8111 if (ds->regex) pcre_free(ds->regex);
8112 if (ds->regex_study) pcre_free(ds->regex_study);
8119 static void data_config_reset(data_unset *d) {
8120 data_config *ds = (data_config *)d;
8123 /* reused array elements */
8124 buffer_reset(ds->key);
8125 buffer_reset(ds->comp_key);
8128 static int data_config_insert_dup(data_unset *dst, data_unset *src) {
8139 array *a = (array *)ds->value;
8144 if (0 == ds->context_ndx) {
8145 fprintf(stderr, "config {\n");
8147 @@ -117,22 +117,22 @@
8149 data_config *data_config_init(void) {
8153 ds = calloc(1, sizeof(*ds));
8156 ds->key = buffer_init();
8157 ds->op = buffer_init();
8158 ds->comp_key = buffer_init();
8159 ds->value = array_init();
8160 ds->childs = array_init();
8161 ds->childs->is_weakref = 1;
8164 ds->copy = data_config_copy;
8165 ds->free = data_config_free;
8166 ds->reset = data_config_reset;
8167 ds->insert_dup = data_config_insert_dup;
8168 ds->print = data_config_print;
8169 ds->type = TYPE_CONFIG;
8174 --- ../lighttpd-1.4.11/src/data_count.c 2005-08-23 17:36:12.000000000 +0300
8175 +++ lighttpd-1.4.12/src/data_count.c 2006-07-16 00:26:03.000000000 +0300
8178 static void data_count_free(data_unset *d) {
8179 data_count *ds = (data_count *)d;
8182 buffer_free(ds->key);
8188 static void data_count_reset(data_unset *d) {
8189 data_count *ds = (data_count *)d;
8192 buffer_reset(ds->key);
8198 static int data_count_insert_dup(data_unset *dst, data_unset *src) {
8199 data_count *ds_dst = (data_count *)dst;
8200 data_count *ds_src = (data_count *)src;
8203 ds_dst->count += ds_src->count;
8212 static void data_count_print(const data_unset *d, int depth) {
8213 data_count *ds = (data_count *)d;
8217 fprintf(stderr, "count(%d)", ds->count);
8221 data_count *data_count_init(void) {
8225 ds = calloc(1, sizeof(*ds));
8228 ds->key = buffer_init();
8232 ds->copy = data_count_copy;
8233 ds->free = data_count_free;
8234 ds->reset = data_count_reset;
8235 ds->insert_dup = data_count_insert_dup;
8236 ds->print = data_count_print;
8237 ds->type = TYPE_COUNT;
8242 --- ../lighttpd-1.4.11/src/data_fastcgi.c 2005-08-23 17:36:12.000000000 +0300
8243 +++ lighttpd-1.4.12/src/data_fastcgi.c 2006-07-16 00:26:04.000000000 +0300
8246 static void data_fastcgi_free(data_unset *d) {
8247 data_fastcgi *ds = (data_fastcgi *)d;
8250 buffer_free(ds->key);
8251 buffer_free(ds->host);
8257 static void data_fastcgi_reset(data_unset *d) {
8258 data_fastcgi *ds = (data_fastcgi *)d;
8261 buffer_reset(ds->key);
8262 buffer_reset(ds->host);
8267 static int data_fastcgi_insert_dup(data_unset *dst, data_unset *src) {
8276 static void data_fastcgi_print(const data_unset *d, int depth) {
8277 data_fastcgi *ds = (data_fastcgi *)d;
8281 fprintf(stderr, "fastcgi(%s)", ds->host->ptr);
8285 data_fastcgi *data_fastcgi_init(void) {
8289 ds = calloc(1, sizeof(*ds));
8292 ds->key = buffer_init();
8293 ds->host = buffer_init();
8295 ds->is_disabled = 0;
8298 ds->copy = data_fastcgi_copy;
8299 ds->free = data_fastcgi_free;
8300 ds->reset = data_fastcgi_reset;
8301 ds->insert_dup = data_fastcgi_insert_dup;
8302 ds->print = data_fastcgi_print;
8303 ds->type = TYPE_FASTCGI;
8308 --- ../lighttpd-1.4.11/src/data_integer.c 2005-08-23 17:36:12.000000000 +0300
8309 +++ lighttpd-1.4.12/src/data_integer.c 2006-07-16 00:26:03.000000000 +0300
8312 static void data_integer_free(data_unset *d) {
8313 data_integer *ds = (data_integer *)d;
8316 buffer_free(ds->key);
8322 static void data_integer_reset(data_unset *d) {
8323 data_integer *ds = (data_integer *)d;
8326 /* reused integer elements */
8327 buffer_reset(ds->key);
8331 static int data_integer_insert_dup(data_unset *dst, data_unset *src) {
8343 data_integer *data_integer_init(void) {
8347 ds = calloc(1, sizeof(*ds));
8350 ds->key = buffer_init();
8354 ds->copy = data_integer_copy;
8355 ds->free = data_integer_free;
8356 ds->reset = data_integer_reset;
8357 ds->insert_dup = data_integer_insert_dup;
8358 ds->print = data_integer_print;
8359 ds->type = TYPE_INTEGER;
8364 --- ../lighttpd-1.4.11/src/data_string.c 2005-08-23 17:36:12.000000000 +0300
8365 +++ lighttpd-1.4.12/src/data_string.c 2006-07-16 00:26:04.000000000 +0300
8368 static void data_string_free(data_unset *d) {
8369 data_string *ds = (data_string *)d;
8372 buffer_free(ds->key);
8373 buffer_free(ds->value);
8379 static void data_string_reset(data_unset *d) {
8380 data_string *ds = (data_string *)d;
8383 /* reused array elements */
8384 buffer_reset(ds->key);
8385 buffer_reset(ds->value);
8387 static int data_string_insert_dup(data_unset *dst, data_unset *src) {
8388 data_string *ds_dst = (data_string *)dst;
8389 data_string *ds_src = (data_string *)src;
8392 if (ds_dst->value->used) {
8393 buffer_append_string(ds_dst->value, ", ");
8394 buffer_append_string_buffer(ds_dst->value, ds_src->value);
8396 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
8406 static int data_response_insert_dup(data_unset *dst, data_unset *src) {
8407 data_string *ds_dst = (data_string *)dst;
8408 data_string *ds_src = (data_string *)src;
8411 if (ds_dst->value->used) {
8412 buffer_append_string(ds_dst->value, "\r\n");
8413 buffer_append_string_buffer(ds_dst->value, ds_dst->key);
8416 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
8428 data_string *data_string_init(void) {
8432 ds = calloc(1, sizeof(*ds));
8436 ds->key = buffer_init();
8437 ds->value = buffer_init();
8440 ds->copy = data_string_copy;
8441 ds->free = data_string_free;
8442 ds->reset = data_string_reset;
8443 ds->insert_dup = data_string_insert_dup;
8444 ds->print = data_string_print;
8445 ds->type = TYPE_STRING;
8451 data_string *data_response_init(void) {
8455 ds = data_string_init();
8456 ds->insert_dup = data_response_insert_dup;
8461 --- ../lighttpd-1.4.11/src/etag.c 2005-08-11 01:26:40.000000000 +0300
8462 +++ lighttpd-1.4.12/src/etag.c 2006-07-18 13:03:40.000000000 +0300
8466 int etag_is_equal(buffer *etag, const char *matches) {
8467 - if (0 == strcmp(etag->ptr, matches)) return 1;
8468 + if (buffer_is_equal_string(etag, matches, strlen(matches))) return 1;
8473 buffer_append_off_t(etag, st->st_size);
8474 buffer_append_string_len(etag, CONST_STR_LEN("-"));
8475 buffer_append_long(etag, st->st_mtime);
8481 int etag_mutate(buffer *mut, buffer *etag) {
8485 for (h=0, i=0; i < etag->used; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
8489 buffer_copy_string_len(mut, CONST_STR_LEN("\""));
8490 buffer_append_long(mut, h);
8491 buffer_append_string_len(mut, CONST_STR_LEN("\""));
8496 --- ../lighttpd-1.4.11/src/etag.h 2005-08-11 01:26:40.000000000 +0300
8497 +++ lighttpd-1.4.12/src/etag.h 2006-07-16 00:26:03.000000000 +0300
8500 #include <sys/types.h>
8501 #include <sys/stat.h>
8502 -#include <unistd.h>
8506 int etag_is_equal(buffer *etag, const char *matches);
8507 int etag_create(buffer *etag, struct stat *st);
8508 int etag_mutate(buffer *mut, buffer *etag);
8513 --- ../lighttpd-1.4.11/src/fastcgi.h 2005-08-11 01:26:40.000000000 +0300
8514 +++ lighttpd-1.4.12/src/fastcgi.h 2006-07-16 00:26:03.000000000 +0300
8520 * Defines for the FastCGI protocol.
8525 - unsigned char type;
8526 + unsigned char type;
8527 unsigned char reserved[7];
8528 } FCGI_UnknownTypeBody;
8530 --- ../lighttpd-1.4.11/src/fdevent.c 2005-11-15 10:51:05.000000000 +0200
8531 +++ lighttpd-1.4.12/src/fdevent.c 2006-07-18 13:03:40.000000000 +0300
8534 #include "settings.h"
8536 -#include <unistd.h>
8540 @@ -11,60 +10,116 @@
8542 #include "fdevent.h"
8546 +#include "sys-socket.h"
8548 +fdevent_revent *fdevent_revent_init(void) {
8549 + STRUCT_INIT(fdevent_revent, revent);
8554 +void fdevent_revent_free(fdevent_revent *revent) {
8555 + if (!revent) return;
8560 +fdevent_revents *fdevent_revents_init(void) {
8561 + STRUCT_INIT(fdevent_revents, revents);
8566 +void fdevent_revents_reset(fdevent_revents *revents) {
8567 + if (!revents) return;
8569 + revents->used = 0;
8572 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events) {
8573 + fdevent_revent *revent;
8575 + if (revents->used == revents->size) {
8576 + /* resize the events-array */
8577 + revents->ptr = realloc(revents->ptr, (revents->size + 1) * sizeof(*(revents->ptr)));
8578 + revents->ptr[revents->size++] = fdevent_revent_init();
8581 + revent = revents->ptr[revents->used++];
8583 + revent->revents = events;
8586 +void fdevent_revents_free(fdevent_revents *revents) {
8589 + if (!revents) return;
8591 + if (revents->size) {
8592 + for (i = 0; i < revents->size; i++) {
8593 + fdevent_revent_free(revents->ptr[i]);
8596 + free(revents->ptr);
8601 fdevents *fdevent_init(size_t maxfds, fdevent_handler_t type) {
8605 ev = calloc(1, sizeof(*ev));
8606 ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray));
8607 ev->maxfds = maxfds;
8611 case FDEVENT_HANDLER_POLL:
8612 if (0 != fdevent_poll_init(ev)) {
8613 - fprintf(stderr, "%s.%d: event-handler poll failed\n",
8614 + fprintf(stderr, "%s.%d: event-handler poll failed\n",
8615 __FILE__, __LINE__);
8621 case FDEVENT_HANDLER_SELECT:
8622 if (0 != fdevent_select_init(ev)) {
8623 - fprintf(stderr, "%s.%d: event-handler select failed\n",
8624 + fprintf(stderr, "%s.%d: event-handler select failed\n",
8625 __FILE__, __LINE__);
8629 case FDEVENT_HANDLER_LINUX_RTSIG:
8630 if (0 != fdevent_linux_rtsig_init(ev)) {
8631 - fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8632 + fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8633 __FILE__, __LINE__);
8637 case FDEVENT_HANDLER_LINUX_SYSEPOLL:
8638 if (0 != fdevent_linux_sysepoll_init(ev)) {
8639 - fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8640 + fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8641 __FILE__, __LINE__);
8645 case FDEVENT_HANDLER_SOLARIS_DEVPOLL:
8646 if (0 != fdevent_solaris_devpoll_init(ev)) {
8647 - fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8648 + fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8649 __FILE__, __LINE__);
8653 case FDEVENT_HANDLER_FREEBSD_KQUEUE:
8654 if (0 != fdevent_freebsd_kqueue_init(ev)) {
8655 - fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8656 + fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8657 __FILE__, __LINE__);
8662 - fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n",
8663 + fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n",
8664 __FILE__, __LINE__);
8667 @@ -75,28 +130,29 @@
8668 void fdevent_free(fdevents *ev) {
8673 if (ev->free) ev->free(ev);
8676 for (i = 0; i < ev->maxfds; i++) {
8677 if (ev->fdarray[i]) free(ev->fdarray[i]);
8685 int fdevent_reset(fdevents *ev) {
8686 if (ev->reset) return ev->reset(ev);
8692 fdnode *fdnode_init() {
8696 fdn = calloc(1, sizeof(*fdn));
8702 @@ -104,48 +160,40 @@
8706 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) {
8707 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx) {
8711 fdn = fdnode_init();
8712 fdn->handler = handler;
8714 + fdn->fd = sock->fd;
8717 - ev->fdarray[fd] = fdn;
8719 + ev->fdarray[sock->fd] = fdn;
8724 -int fdevent_unregister(fdevents *ev, int fd) {
8725 +int fdevent_unregister(fdevents *ev, iosocket *sock) {
8728 - fdn = ev->fdarray[fd];
8730 + fdn = ev->fdarray[sock->fd];
8734 - ev->fdarray[fd] = NULL;
8737 + ev->fdarray[sock->fd] = NULL;
8742 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd) {
8743 - int fde = fde_ndx ? *fde_ndx : -1;
8745 - if (ev->event_del) fde = ev->event_del(ev, fde, fd);
8747 - if (fde_ndx) *fde_ndx = fde;
8749 +int fdevent_event_del(fdevents *ev, iosocket *sock) {
8750 + if (ev->event_del) ev->event_del(ev, sock);
8755 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events) {
8756 - int fde = fde_ndx ? *fde_ndx : -1;
8758 - if (ev->event_add) fde = ev->event_add(ev, fde, fd, events);
8760 - if (fde_ndx) *fde_ndx = fde;
8762 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events) {
8763 + if (ev->event_add) ev->event_add(ev, sock, events);
8768 @@ -154,49 +202,41 @@
8769 return ev->poll(ev, timeout_ms);
8772 -int fdevent_event_get_revent(fdevents *ev, size_t ndx) {
8773 - if (ev->event_get_revent == NULL) SEGFAULT();
8775 - return ev->event_get_revent(ev, ndx);
8777 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
8780 -int fdevent_event_get_fd(fdevents *ev, size_t ndx) {
8781 - if (ev->event_get_fd == NULL) SEGFAULT();
8783 - return ev->event_get_fd(ev, ndx);
8785 + if (ev->get_revents == NULL) SEGFAULT();
8787 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd) {
8788 - if (ev->fdarray[fd] == NULL) SEGFAULT();
8789 - if (ev->fdarray[fd]->fd != fd) SEGFAULT();
8791 - return ev->fdarray[fd]->handler;
8793 + fdevent_revents_reset(revents);
8795 -void * fdevent_get_context(fdevents *ev, int fd) {
8796 - if (ev->fdarray[fd] == NULL) SEGFAULT();
8797 - if (ev->fdarray[fd]->fd != fd) SEGFAULT();
8799 - return ev->fdarray[fd]->ctx;
8800 + ev->get_revents(ev, event_count, revents);
8802 + /* patch the event handlers */
8803 + for (i = 0; i < event_count; i++) {
8804 + fdevent_revent *r = revents->ptr[i];
8806 + r->handler = ev->fdarray[r->fd]->handler;
8807 + r->context = ev->fdarray[r->fd]->ctx;
8813 -int fdevent_fcntl_set(fdevents *ev, int fd) {
8814 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock) {
8819 /* close fd on exec (cgi) */
8820 - fcntl(fd, F_SETFD, FD_CLOEXEC);
8821 + fcntl(sock->fd, F_SETFD, FD_CLOEXEC);
8823 - if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, fd);
8825 - return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
8826 + if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, sock->fd);
8828 + return fcntl(sock->fd, F_SETFL, O_NONBLOCK | O_RDWR);
8829 +#elif defined _WIN32
8830 + return ioctlsocket(sock->fd, FIONBIO, &i);
8837 -int fdevent_event_next_fdndx(fdevents *ev, int ndx) {
8838 - if (ev->event_next_fdndx) return ev->event_next_fdndx(ev, ndx);
8843 --- ../lighttpd-1.4.11/src/fdevent.h 2005-09-27 11:26:33.000000000 +0300
8844 +++ lighttpd-1.4.12/src/fdevent.h 2006-07-18 13:03:40.000000000 +0300
8846 #include "settings.h"
8849 +#include "iosocket.h"
8850 +#include "array-static.h"
8852 /* select event-system */
8854 #if defined(HAVE_EPOLL_CTL) && defined(HAVE_SYS_EPOLL_H)
8856 # include <sys/epoll.h>
8859 -/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes
8860 +/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes
8861 * under /usr/include/sys/ */
8862 #if defined HAVE_POLL && (defined(HAVE_SYS_POLL_H) || defined(HAVE_POLL_H))
8868 # include <sys/poll.h>
8870 # if defined HAVE_SIGTIMEDWAIT && defined(__linux__)
8872 # include <signal.h>
8877 +# define HAVE_SELECT
8879 #if defined HAVE_SELECT
8882 # include <winsock2.h>
8886 #define FDEVENT_HUP BV(4)
8887 #define FDEVENT_NVAL BV(5)
8889 -typedef enum { FD_EVENT_TYPE_UNSET = -1,
8890 - FD_EVENT_TYPE_CONNECTION,
8891 - FD_EVENT_TYPE_FCGI_CONNECTION,
8892 - FD_EVENT_TYPE_DIRWATCH,
8893 - FD_EVENT_TYPE_CGI_CONNECTION
8894 +typedef enum { FD_EVENT_TYPE_UNSET = -1,
8895 + FD_EVENT_TYPE_CONNECTION,
8896 + FD_EVENT_TYPE_FCGI_CONNECTION,
8897 + FD_EVENT_TYPE_DIRWATCH,
8898 + FD_EVENT_TYPE_CGI_CONNECTION
8901 -typedef enum { FDEVENT_HANDLER_UNSET,
8902 +typedef enum { FDEVENT_HANDLER_UNSET,
8903 FDEVENT_HANDLER_SELECT,
8904 FDEVENT_HANDLER_POLL,
8905 FDEVENT_HANDLER_LINUX_RTSIG,
8909 * a mapping from fd to connection structure
8914 int fd; /**< the fd */
8915 @@ -96,43 +101,51 @@
8919 +ARRAY_STATIC_DEF(fd_conn_buffer, fd_conn, );
8933 + fdevent_handler handler;
8937 +ARRAY_STATIC_DEF(fdevent_revents, fdevent_revent, );
8940 * array of unused fd's
8945 typedef struct _fdnode {
8946 - fdevent_handler handler;
8950 + fdevent_handler handler; /* who handles the events for this fd */
8951 + void *ctx; /* opaque pointer which is passed as 3rd parameter to the handler */
8954 struct _fdnode *prev, *next;
8966 * fd-event handler for select(), poll() and rt-signals on Linux 2.4
8970 typedef struct fdevents {
8971 fdevent_handler_t type;
8975 + fdnode **fdarray; /* a list of fdnodes */
8979 #ifdef USE_LINUX_SIGIO
8982 @@ -146,21 +159,21 @@
8985 struct pollfd *pollfds;
8996 fd_set select_write;
8997 fd_set select_error;
9000 fd_set select_set_read;
9001 fd_set select_set_write;
9002 fd_set select_set_error;
9007 #ifdef USE_SOLARIS_DEVPOLL
9008 @@ -177,16 +190,13 @@
9010 int (*reset)(struct fdevents *ev);
9011 void (*free)(struct fdevents *ev);
9013 - int (*event_add)(struct fdevents *ev, int fde_ndx, int fd, int events);
9014 - int (*event_del)(struct fdevents *ev, int fde_ndx, int fd);
9015 - int (*event_get_revent)(struct fdevents *ev, size_t ndx);
9016 - int (*event_get_fd)(struct fdevents *ev, size_t ndx);
9018 - int (*event_next_fdndx)(struct fdevents *ev, int ndx);
9021 + int (*event_add)(struct fdevents *ev, iosocket *sock, int events);
9022 + int (*event_del)(struct fdevents *ev, iosocket *sock);
9023 + int (*get_revents)(struct fdevents *ev, size_t event_count, fdevent_revents *revents);
9025 int (*poll)(struct fdevents *ev, int timeout_ms);
9028 int (*fcntl_set)(struct fdevents *ev, int fd);
9031 @@ -194,22 +204,44 @@
9032 int fdevent_reset(fdevents *ev);
9033 void fdevent_free(fdevents *ev);
9035 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events);
9036 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd);
9037 -int fdevent_event_get_revent(fdevents *ev, size_t ndx);
9038 -int fdevent_event_get_fd(fdevents *ev, size_t ndx);
9039 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd);
9040 -void * fdevent_get_context(fdevents *ev, int fd);
9042 + * call the plugin for the number of available events
9044 +int fdevent_poll(fdevents *ev, int timeout_ms);
9046 + * get all available events
9048 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents);
9050 -int fdevent_event_next_fdndx(fdevents *ev, int ndx);
9052 + * add or remove a fd to the handled-pool
9054 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx);
9055 +int fdevent_unregister(fdevents *ev, iosocket *sock);
9057 -int fdevent_poll(fdevents *ev, int timeout_ms);
9059 + * add a event to a registered fd
9061 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events);
9062 +int fdevent_event_del(fdevents *ev, iosocket *sock);
9065 + * set non-blocking
9067 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock);
9069 +fdevent_revents *fdevent_revents_init(void);
9070 +void fdevent_revents_reset(fdevent_revents *revents);
9071 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events);
9072 +void fdevent_revents_free(fdevent_revents *revents);
9074 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx);
9075 -int fdevent_unregister(fdevents *ev, int fd);
9076 +fdevent_revent *fdevent_revent_init(void);
9077 +void fdevent_revent_free(fdevent_revent *revent);
9079 -int fdevent_fcntl_set(fdevents *ev, int fd);
9084 int fdevent_select_init(fdevents *ev);
9085 int fdevent_poll_init(fdevents *ev);
9086 int fdevent_linux_rtsig_init(fdevents *ev);
9087 --- ../lighttpd-1.4.11/src/fdevent_freebsd_kqueue.c 2005-09-01 10:46:24.000000000 +0300
9088 +++ lighttpd-1.4.12/src/fdevent_freebsd_kqueue.c 2006-07-16 00:26:03.000000000 +0300
9090 #include <sys/types.h>
9092 -#include <unistd.h>
9111 ret = kevent(ev->kq_fd,
9120 if (filter == EVFILT_READ) {
9121 bitset_set_bit(ev->kq_bevents, fd);
9124 } else if (e == EVFILT_WRITE) {
9125 events |= FDEVENT_OUT;
9129 e = ev->kq_results[ndx].flags;
9132 @@ -152,10 +151,10 @@
9133 if (-1 == (ev->kq_fd = kqueue())) {
9134 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9135 __FILE__, __LINE__, strerror(errno));
9146 if (-1 == (ev->kq_fd = kqueue())) {
9147 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9148 __FILE__, __LINE__, strerror(errno));
9154 --- ../lighttpd-1.4.11/src/fdevent_linux_rtsig.c 2005-11-21 19:56:11.000000000 +0200
9155 +++ lighttpd-1.4.12/src/fdevent_linux_rtsig.c 2006-07-18 13:03:40.000000000 +0300
9157 #include <sys/types.h>
9159 -#include <unistd.h>
9164 #include "fdevent.h"
9165 #include "settings.h"
9167 +#include "sys-process.h"
9170 #ifdef USE_LINUX_SIGIO
9171 static void fdevent_linux_rtsig_free(fdevents *ev) {
9176 -static int fdevent_linux_rtsig_event_del(fdevents *ev, int fde_ndx, int fd) {
9177 - if (fde_ndx < 0) return -1;
9179 - if ((size_t)fde_ndx >= ev->used) {
9180 - fprintf(stderr, "%s.%d: del! out of range %d %zu\n", __FILE__, __LINE__, fde_ndx, ev->used);
9181 +static int fdevent_linux_rtsig_event_del(fdevents *ev, iosocket *sock) {
9182 + if (sock->fde_ndx < 0) return -1;
9184 + if ((size_t)sock->fde_ndx >= ev->used) {
9185 + TRACE("del! out of range %d %zu\n", sock->fde_ndx, ev->used);
9189 - if (ev->pollfds[fde_ndx].fd == fd) {
9190 - size_t k = fde_ndx;
9193 + if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9194 + size_t k = sock->fde_ndx;
9196 ev->pollfds[k].fd = -1;
9198 - bitset_clear_bit(ev->sigbset, fd);
9200 + bitset_clear_bit(ev->sigbset, sock->fd);
9202 if (ev->unused.size == 0) {
9203 ev->unused.size = 16;
9204 ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
9206 ev->unused.size += 16;
9207 ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
9211 ev->unused.ptr[ev->unused.used++] = k;
9213 - fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[fde_ndx].fd, fd);
9215 + fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[sock->fde_ndx].fd, sock->fd);
9221 + sock->fde_ndx = -1;
9227 static int fdevent_linux_rtsig_event_compress(fdevents *ev) {
9231 if (ev->used == 0) return 0;
9232 if (ev->unused.used != 0) return 0;
9235 for (j = ev->used - 1; j + 1 > 0; j--) {
9236 if (ev->pollfds[j].fd == -1) ev->used--;
9246 -static int fdevent_linux_rtsig_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9247 +static int fdevent_linux_rtsig_event_add(fdevents *ev, iosocket *sock, int events) {
9249 - if (fde_ndx != -1) {
9250 - if (ev->pollfds[fde_ndx].fd == fd) {
9251 - ev->pollfds[fde_ndx].events = events;
9254 + if (sock->fde_ndx != -1) {
9255 + if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9256 + ev->pollfds[sock->fde_ndx].events = events;
9258 + return sock->fde_ndx;
9260 - fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
9261 + fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
9266 if (ev->unused.used > 0) {
9267 int k = ev->unused.ptr[--ev->unused.used];
9269 - ev->pollfds[k].fd = fd;
9271 + ev->pollfds[k].fd = sock->fd;
9272 ev->pollfds[k].events = events;
9274 - bitset_set_bit(ev->sigbset, fd);
9276 + bitset_set_bit(ev->sigbset, sock->fd);
9280 if (ev->size == 0) {
9281 @@ -102,12 +104,12 @@
9283 ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
9286 - ev->pollfds[ev->used].fd = fd;
9288 + ev->pollfds[ev->used].fd = sock->fd;
9289 ev->pollfds[ev->used].events = events;
9291 - bitset_set_bit(ev->sigbset, fd);
9293 + bitset_set_bit(ev->sigbset, sock->fd);
9298 @@ -115,20 +117,20 @@
9299 static int fdevent_linux_rtsig_poll(fdevents *ev, int timeout_ms) {
9305 fdevent_linux_rtsig_event_compress(ev);
9312 ts.tv_sec = timeout_ms / 1000;
9313 ts.tv_nsec = (timeout_ms % 1000) * 1000000;
9314 r = sigtimedwait(&(ev->sigset), &(ev->siginfo), &(ts));
9319 if (errno == EAGAIN) return 0;
9322 } else if (r == SIGIO) {
9323 struct sigaction act;
9326 /* re-enable the signal queue */
9327 act.sa_handler = SIG_DFL;
9328 sigaction(ev->signum, &act, NULL);
9332 r = poll(ev->pollfds, ev->used, timeout_ms);
9334 @@ -156,97 +158,67 @@
9338 -static int fdevent_linux_rtsig_event_get_revent(fdevents *ev, size_t ndx) {
9339 +static int fdevent_linux_rtsig_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9340 if (ev->in_sigio == 1) {
9342 - if (ev->siginfo.si_band == POLLERR) {
9343 - fprintf(stderr, "event: %d %02lx %02x %s\n", ev->siginfo.si_fd, ev->siginfo.si_band, errno, strerror(errno));
9347 - fprintf(stderr, "+\n");
9351 - return ev->siginfo.si_band & 0x3f;
9352 + /* only one event */
9354 + fdevent_revents_add(revents, ev->siginfo.si_fd, ev->siginfo.si_band & 0x3f);
9356 - if (ndx >= ev->used) {
9357 - fprintf(stderr, "%s.%d: event: %zu %zu\n", __FILE__, __LINE__, ndx, ev->used);
9361 + for (ndx = 0; ndx < ev->used; ndx++) {
9362 + if (ev->pollfds[ndx].revents) {
9363 + fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
9366 - return ev->pollfds[ndx].revents;
9370 -static int fdevent_linux_rtsig_event_get_fd(fdevents *ev, size_t ndx) {
9371 - if (ev->in_sigio == 1) {
9372 - return ev->siginfo.si_fd;
9374 - return ev->pollfds[ndx].fd;
9379 static int fdevent_linux_rtsig_fcntl_set(fdevents *ev, int fd) {
9380 static pid_t pid = 0;
9383 if (pid == 0) pid = getpid();
9386 if (-1 == fcntl(fd, F_SETSIG, ev->signum)) return -1;
9389 if (-1 == fcntl(fd, F_SETOWN, (int) pid)) return -1;
9392 return fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK | O_RDWR);
9396 -static int fdevent_linux_rtsig_event_next_fdndx(fdevents *ev, int ndx) {
9397 - if (ev->in_sigio == 1) {
9398 - if (ndx < 0) return 0;
9403 - i = (ndx < 0) ? 0 : ndx + 1;
9404 - for (; i < ev->used; i++) {
9405 - if (ev->pollfds[i].revents) break;
9412 int fdevent_linux_rtsig_init(fdevents *ev) {
9413 ev->type = FDEVENT_HANDLER_LINUX_RTSIG;
9415 ev->x = fdevent_linux_rtsig_##x;
9425 - SET(event_next_fdndx);
9428 - SET(event_get_fd);
9429 - SET(event_get_revent);
9433 ev->signum = SIGRTMIN + 1;
9436 sigemptyset(&(ev->sigset));
9437 sigaddset(&(ev->sigset), ev->signum);
9438 sigaddset(&(ev->sigset), SIGIO);
9439 if (-1 == sigprocmask(SIG_BLOCK, &(ev->sigset), NULL)) {
9440 fprintf(stderr, "%s.%d: sigprocmask failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9441 __FILE__, __LINE__, strerror(errno));
9450 ev->sigbset = bitset_init(ev->maxfds);
9456 --- ../lighttpd-1.4.11/src/fdevent_linux_sysepoll.c 2005-09-30 20:29:27.000000000 +0300
9457 +++ lighttpd-1.4.12/src/fdevent_linux_sysepoll.c 2006-07-18 13:03:40.000000000 +0300
9459 #include <sys/types.h>
9461 -#include <unistd.h>
9466 #include "fdevent.h"
9467 #include "settings.h"
9471 +#include "sys-files.h"
9473 #ifdef USE_LINUX_EPOLL
9474 static void fdevent_linux_sysepoll_free(fdevents *ev) {
9476 free(ev->epoll_events);
9479 -static int fdevent_linux_sysepoll_event_del(fdevents *ev, int fde_ndx, int fd) {
9480 +static int fdevent_linux_sysepoll_event_del(fdevents *ev, iosocket *sock) {
9481 struct epoll_event ep;
9483 - if (fde_ndx < 0) return -1;
9486 + if (sock->fde_ndx < 0) return -1;
9488 memset(&ep, 0, sizeof(ep));
9492 + ep.data.fd = sock->fd;
9495 - if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fd, &ep)) {
9497 + if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, sock->fd, &ep)) {
9498 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
9510 + sock->fde_ndx = -1;
9515 -static int fdevent_linux_sysepoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9516 +static int fdevent_linux_sysepoll_event_add(fdevents *ev, iosocket *sock, int events) {
9517 struct epoll_event ep;
9520 - if (fde_ndx == -1) add = 1;
9524 + if (sock->fde_ndx == -1) add = 1;
9526 memset(&ep, 0, sizeof(ep));
9532 if (events & FDEVENT_IN) ep.events |= EPOLLIN;
9533 if (events & FDEVENT_OUT) ep.events |= EPOLLOUT;
9541 ep.events |= EPOLLERR | EPOLLHUP /* | EPOLLET */;
9547 - if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &ep)) {
9548 + ep.data.fd = sock->fd;
9550 + if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, sock->fd, &ep)) {
9551 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
9562 + sock->fde_ndx = sock->fd;
9567 static int fdevent_linux_sysepoll_poll(fdevents *ev, int timeout_ms) {
9568 return epoll_wait(ev->epoll_fd, ev->epoll_events, ev->maxfds, timeout_ms);
9571 -static int fdevent_linux_sysepoll_event_get_revent(fdevents *ev, size_t ndx) {
9572 - int events = 0, e;
9574 - e = ev->epoll_events[ndx].events;
9575 - if (e & EPOLLIN) events |= FDEVENT_IN;
9576 - if (e & EPOLLOUT) events |= FDEVENT_OUT;
9577 - if (e & EPOLLERR) events |= FDEVENT_ERR;
9578 - if (e & EPOLLHUP) events |= FDEVENT_HUP;
9579 - if (e & EPOLLPRI) events |= FDEVENT_PRI;
9584 -static int fdevent_linux_sysepoll_event_get_fd(fdevents *ev, size_t ndx) {
9586 - fprintf(stderr, "%s.%d: %d, %d\n", __FILE__, __LINE__, ndx, ev->epoll_events[ndx].data.fd);
9589 - return ev->epoll_events[ndx].data.fd;
9592 -static int fdevent_linux_sysepoll_event_next_fdndx(fdevents *ev, int ndx) {
9596 +static int fdevent_linux_sysepoll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9599 + for (ndx = 0; ndx < event_count; ndx++) {
9600 + int events = 0, e;
9602 + e = ev->epoll_events[ndx].events;
9603 + if (e & EPOLLIN) events |= FDEVENT_IN;
9604 + if (e & EPOLLOUT) events |= FDEVENT_OUT;
9605 + if (e & EPOLLERR) events |= FDEVENT_ERR;
9606 + if (e & EPOLLHUP) events |= FDEVENT_HUP;
9607 + if (e & EPOLLPRI) events |= FDEVENT_PRI;
9609 - i = (ndx < 0) ? 0 : ndx + 1;
9612 + fdevent_revents_add(revents, ev->epoll_events[ndx].data.fd, e);
9618 int fdevent_linux_sysepoll_init(fdevents *ev) {
9619 ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
9621 ev->x = fdevent_linux_sysepoll_##x;
9631 - SET(event_next_fdndx);
9632 - SET(event_get_fd);
9633 - SET(event_get_revent);
9638 if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) {
9639 fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9640 __FILE__, __LINE__, strerror(errno));
9643 fprintf(stderr, "%s.%d: linux-sysepoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
9644 __FILE__, __LINE__);
9650 --- ../lighttpd-1.4.11/src/fdevent_poll.c 2005-11-18 13:59:16.000000000 +0200
9651 +++ lighttpd-1.4.12/src/fdevent_poll.c 2006-07-18 13:03:40.000000000 +0300
9653 #include <sys/types.h>
9655 -#include <unistd.h>
9660 #include "fdevent.h"
9661 #include "settings.h"
9666 static void fdevent_poll_free(fdevents *ev) {
9668 if (ev->unused.ptr) free(ev->unused.ptr);
9671 -static int fdevent_poll_event_del(fdevents *ev, int fde_ndx, int fd) {
9672 - if (fde_ndx < 0) return -1;
9674 - if ((size_t)fde_ndx >= ev->used) {
9675 - fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, fde_ndx, ev->used);
9676 +static int fdevent_poll_event_del(fdevents *ev, iosocket *sock) {
9677 + if (sock->fde_ndx < 0) return -1;
9679 + if ((size_t)sock->fde_ndx >= ev->used) {
9680 + fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, sock->fde_ndx, ev->used);
9684 - if (ev->pollfds[fde_ndx].fd == fd) {
9685 - size_t k = fde_ndx;
9688 + if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9689 + size_t k = sock->fde_ndx;
9691 ev->pollfds[k].fd = -1;
9692 /* ev->pollfds[k].events = 0; */
9693 /* ev->pollfds[k].revents = 0; */
9696 if (ev->unused.size == 0) {
9697 ev->unused.size = 16;
9698 ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
9700 ev->unused.size += 16;
9701 ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
9705 ev->unused.ptr[ev->unused.used++] = k;
9712 + sock->fde_ndx = -1;
9718 static int fdevent_poll_event_compress(fdevents *ev) {
9722 if (ev->used == 0) return 0;
9723 if (ev->unused.used != 0) return 0;
9726 for (j = ev->used - 1; j + 1 > 0 && ev->pollfds[j].fd == -1; j--) ev->used--;
9733 -static int fdevent_poll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9736 - if (fde_ndx != -1) {
9737 - if (ev->pollfds[fde_ndx].fd == fd) {
9738 - ev->pollfds[fde_ndx].events = events;
9741 +static int fdevent_poll_event_add(fdevents *ev, iosocket *sock, int events) {
9742 + if (sock->fde_ndx != -1) {
9743 + /* this fd was already added, just change the requested events */
9745 + if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9746 + ev->pollfds[sock->fde_ndx].events = events;
9748 + return sock->fde_ndx;
9750 - fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
9751 + fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
9756 if (ev->unused.used > 0) {
9757 int k = ev->unused.ptr[--ev->unused.used];
9759 - ev->pollfds[k].fd = fd;
9761 + ev->pollfds[k].fd = sock->fd;
9762 ev->pollfds[k].events = events;
9766 + sock->fde_ndx = k;
9769 if (ev->size == 0) {
9773 ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
9776 - ev->pollfds[ev->used].fd = fd;
9778 + ev->pollfds[ev->used].fd = sock->fd;
9779 ev->pollfds[ev->used].events = events;
9781 - return ev->used++;
9783 + sock->fde_ndx = ev->used++;
9788 static int fdevent_poll_poll(fdevents *ev, int timeout_ms) {
9789 @@ -105,71 +109,38 @@
9790 return poll(ev->pollfds, ev->used, timeout_ms);
9793 -static int fdevent_poll_event_get_revent(fdevents *ev, size_t ndx) {
9795 - if (ndx >= ev->used) {
9796 - fprintf(stderr, "%s.%d: dying because: event: %zd >= %zd\n", __FILE__, __LINE__, ndx, ev->used);
9803 - if (ev->pollfds[ndx].revents & POLLNVAL) {
9804 - /* should never happen */
9807 +static int fdevent_poll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9811 - poll_r = ev->pollfds[ndx].revents;
9812 + for (ndx = 0; ndx < ev->used; ndx++) {
9813 + if (ev->pollfds[ndx].revents) {
9814 + if (ev->pollfds[ndx].revents & POLLNVAL) {
9815 + /* should never happen */
9819 - /* map POLL* to FDEVEN_* */
9821 - if (poll_r & POLLIN) r |= FDEVENT_IN;
9822 - if (poll_r & POLLOUT) r |= FDEVENT_OUT;
9823 - if (poll_r & POLLERR) r |= FDEVENT_ERR;
9824 - if (poll_r & POLLHUP) r |= FDEVENT_HUP;
9825 - if (poll_r & POLLNVAL) r |= FDEVENT_NVAL;
9826 - if (poll_r & POLLPRI) r |= FDEVENT_PRI;
9828 - return ev->pollfds[ndx].revents;
9831 -static int fdevent_poll_event_get_fd(fdevents *ev, size_t ndx) {
9832 - return ev->pollfds[ndx].fd;
9835 -static int fdevent_poll_event_next_fdndx(fdevents *ev, int ndx) {
9838 - i = (ndx < 0) ? 0 : ndx + 1;
9839 - for (; i < ev->used; i++) {
9840 - if (ev->pollfds[i].revents) break;
9841 + fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
9850 int fdevent_poll_init(fdevents *ev) {
9851 ev->type = FDEVENT_HANDLER_POLL;
9853 ev->x = fdevent_poll_##x;
9863 - SET(event_next_fdndx);
9864 - SET(event_get_fd);
9865 - SET(event_get_revent);
9877 int fdevent_poll_init(fdevents *ev) {
9878 --- ../lighttpd-1.4.11/src/fdevent_select.c 2005-08-31 11:12:46.000000000 +0300
9879 +++ lighttpd-1.4.12/src/fdevent_select.c 2006-07-18 13:03:40.000000000 +0300
9881 -#include <sys/time.h>
9882 #include <sys/types.h>
9884 -#include <unistd.h>
9893 #include "fdevent.h"
9894 #include "settings.h"
9897 +#include "sys-socket.h"
9901 static int fdevent_select_reset(fdevents *ev) {
9902 @@ -24,101 +25,98 @@
9906 -static int fdevent_select_event_del(fdevents *ev, int fde_ndx, int fd) {
9907 - if (fde_ndx < 0) return -1;
9908 +static int fdevent_select_event_del(fdevents *ev, iosocket *sock) {
9909 + if (sock->fde_ndx < 0) return -1;
9911 - FD_CLR(fd, &(ev->select_set_read));
9912 - FD_CLR(fd, &(ev->select_set_write));
9913 - FD_CLR(fd, &(ev->select_set_error));
9914 + FD_CLR(sock->fd, &(ev->select_set_read));
9915 + FD_CLR(sock->fd, &(ev->select_set_write));
9916 + FD_CLR(sock->fd, &(ev->select_set_error));
9920 + /* mark the fdevent as deleted */
9921 + sock->fde_ndx = -1;
9923 -static int fdevent_select_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9928 +static int fdevent_select_event_add(fdevents *ev, iosocket *sock, int events) {
9929 /* we should be protected by max-fds, but you never know */
9930 - assert(fd < FD_SETSIZE);
9932 + assert(sock->fd < FD_SETSIZE);
9935 if (events & FDEVENT_IN) {
9936 - FD_SET(fd, &(ev->select_set_read));
9937 - FD_CLR(fd, &(ev->select_set_write));
9938 + FD_SET(sock->fd, &(ev->select_set_read));
9939 + FD_CLR(sock->fd, &(ev->select_set_write));
9941 if (events & FDEVENT_OUT) {
9942 - FD_CLR(fd, &(ev->select_set_read));
9943 - FD_SET(fd, &(ev->select_set_write));
9944 + FD_CLR(sock->fd, &(ev->select_set_read));
9945 + FD_SET(sock->fd, &(ev->select_set_write));
9947 - FD_SET(fd, &(ev->select_set_error));
9949 - if (fd > ev->select_max_fd) ev->select_max_fd = fd;
9952 + FD_SET(sock->fd, &(ev->select_set_error));
9954 + /* we need this for the poll */
9955 + if (sock->fd > ev->select_max_fd) ev->select_max_fd = sock->fd;
9957 + /* mark fd as added */
9958 + sock->fde_ndx = sock->fd;
9963 static int fdevent_select_poll(fdevents *ev, int timeout_ms) {
9967 tv.tv_sec = timeout_ms / 1000;
9968 tv.tv_usec = (timeout_ms % 1000) * 1000;
9971 ev->select_read = ev->select_set_read;
9972 ev->select_write = ev->select_set_write;
9973 ev->select_error = ev->select_set_error;
9976 return select(ev->select_max_fd + 1, &(ev->select_read), &(ev->select_write), &(ev->select_error), &tv);
9979 -static int fdevent_select_event_get_revent(fdevents *ev, size_t ndx) {
9982 - if (FD_ISSET(ndx, &(ev->select_read))) {
9983 - revents |= FDEVENT_IN;
9985 + * scan the fdset for events
9987 +static int fdevent_select_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9991 + for (ndx = 0; ndx < ev->select_max_fd; ndx++) {
9994 + if (FD_ISSET(ndx, &(ev->select_read))) {
9995 + events |= FDEVENT_IN;
9997 + if (FD_ISSET(ndx, &(ev->select_write))) {
9998 + events |= FDEVENT_OUT;
10000 + if (FD_ISSET(ndx, &(ev->select_error))) {
10001 + events |= FDEVENT_ERR;
10005 + fdevent_revents_add(revents, ndx, events);
10008 - if (FD_ISSET(ndx, &(ev->select_write))) {
10009 - revents |= FDEVENT_OUT;
10011 - if (FD_ISSET(ndx, &(ev->select_error))) {
10012 - revents |= FDEVENT_ERR;
10018 -static int fdevent_select_event_get_fd(fdevents *ev, size_t ndx) {
10024 -static int fdevent_select_event_next_fdndx(fdevents *ev, int ndx) {
10027 - i = (ndx < 0) ? 0 : ndx + 1;
10029 - for (; i < ev->select_max_fd + 1; i++) {
10030 - if (FD_ISSET(i, &(ev->select_read))) break;
10031 - if (FD_ISSET(i, &(ev->select_write))) break;
10032 - if (FD_ISSET(i, &(ev->select_error))) break;
10039 int fdevent_select_init(fdevents *ev) {
10040 ev->type = FDEVENT_HANDLER_SELECT;
10042 ev->x = fdevent_select_##x;
10052 - SET(event_next_fdndx);
10053 - SET(event_get_fd);
10054 - SET(event_get_revent);
10057 + SET(get_revents);
10062 --- ../lighttpd-1.4.11/src/fdevent_solaris_devpoll.c 2005-09-01 10:45:26.000000000 +0300
10063 +++ lighttpd-1.4.12/src/fdevent_solaris_devpoll.c 2006-07-16 00:26:03.000000000 +0300
10065 #include <sys/types.h>
10067 -#include <unistd.h>
10068 #include <stdlib.h>
10070 #include <string.h>
10071 @@ -23,55 +22,55 @@
10073 static int fdevent_solaris_devpoll_event_del(fdevents *ev, int fde_ndx, int fd) {
10077 if (fde_ndx < 0) return -1;
10081 pfd.events = POLLREMOVE;
10085 if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
10086 - fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10087 - __FILE__, __LINE__,
10088 + fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10089 + __FILE__, __LINE__,
10090 fd, strerror(errno));
10100 static int fdevent_solaris_devpoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
10105 if (fde_ndx == -1) add = 1;
10109 pfd.events = events;
10113 if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
10114 - fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10115 - __FILE__, __LINE__,
10116 + fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10117 + __FILE__, __LINE__,
10118 fd, strerror(errno));
10128 static int fdevent_solaris_devpoll_poll(fdevents *ev, int timeout_ms) {
10129 struct dvpoll dopoll;
10133 dopoll.dp_timeout = timeout_ms;
10134 dopoll.dp_nfds = ev->maxfds;
10135 dopoll.dp_fds = ev->devpollfds;
10138 ret = ioctl(ev->devpoll_fd, DP_POLL, &dopoll);
10144 @@ -85,11 +84,11 @@
10146 static int fdevent_solaris_devpoll_event_next_fdndx(fdevents *ev, int last_ndx) {
10152 i = (last_ndx < 0) ? 0 : last_ndx + 1;
10158 @@ -117,20 +116,20 @@
10159 ev->type = FDEVENT_HANDLER_SOLARIS_DEVPOLL;
10161 ev->x = fdevent_solaris_devpoll_##x;
10173 SET(event_next_fdndx);
10175 SET(event_get_revent);
10178 ev->devpollfds = malloc(sizeof(*ev->devpollfds) * ev->maxfds);
10181 if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
10182 fprintf(stderr, "%s.%d: opening /dev/poll failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
10183 __FILE__, __LINE__, strerror(errno));
10184 @@ -152,7 +151,7 @@
10186 fprintf(stderr, "%s.%d: solaris-devpoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
10187 __FILE__, __LINE__);
10193 --- ../lighttpd-1.4.11/src/http-header-glue.c 2006-02-08 15:31:36.000000000 +0200
10194 +++ lighttpd-1.4.12/src/http-header-glue.c 2006-07-18 13:03:40.000000000 +0300
10195 @@ -45,20 +45,20 @@
10196 # ifdef HAVE_STRUCT_SOCKADDR_STORAGE
10197 static size_t get_sa_len(const struct sockaddr *addr) {
10198 switch (addr->sa_family) {
10203 return (sizeof (struct sockaddr_in));
10209 return (sizeof (struct sockaddr_in6));
10214 return (sizeof (struct sockaddr));
10219 # define SA_LEN(addr) (get_sa_len(addr))
10222 int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
10228 if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
10229 @@ -82,32 +82,32 @@
10231 buffer_copy_string_len(ds->key, key, keylen);
10232 buffer_copy_string_len(ds->value, value, vallen);
10235 array_insert_unique(con->response.headers, (data_unset *)ds);
10241 int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
10247 /* if there already is a key by this name overwrite the value */
10248 if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key))) {
10249 buffer_copy_string(ds->value, value);
10256 return response_header_insert(srv, con, key, keylen, value, vallen);
10259 int http_response_redirect_to_directory(server *srv, connection *con) {
10266 if (con->conf.is_ssl) {
10267 buffer_copy_string(o, "https://");
10269 @@ -123,36 +123,36 @@
10271 sock_addr our_addr;
10272 socklen_t our_addr_len;
10275 our_addr_len = sizeof(our_addr);
10277 - if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
10279 + if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
10280 con->http_status = 500;
10283 log_error_write(srv, __FILE__, __LINE__, "ss",
10284 "can't get sockname", strerror(errno));
10294 /* Lookup name: secondly try to get hostname for bind address */
10295 switch(our_addr.plain.sa_family) {
10298 - if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
10299 - SA_LEN((const struct sockaddr *)&our_addr.ipv6),
10300 + if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
10301 + SA_LEN((const struct sockaddr *)&our_addr.ipv6),
10302 hbuf, sizeof(hbuf), NULL, 0, 0)) {
10305 char dst[INET6_ADDRSTRLEN];
10308 log_error_write(srv, __FILE__, __LINE__,
10309 "SSSS", "NOTICE: getnameinfo failed: ",
10310 strerror(errno), ", using ip-address instead");
10312 - buffer_append_string(o,
10313 - inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
10315 + buffer_append_string(o,
10316 + inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
10317 dst, sizeof(dst)));
10319 buffer_append_string(o, hbuf);
10320 @@ -164,7 +164,7 @@
10321 log_error_write(srv, __FILE__, __LINE__,
10322 "SdSS", "NOTICE: gethostbyaddr failed: ",
10323 h_errno, ", using ip-address instead");
10326 buffer_append_string(o, inet_ntoa(our_addr.ipv4.sin_addr));
10328 buffer_append_string(o, he->h_name);
10329 @@ -173,12 +173,12 @@
10331 log_error_write(srv, __FILE__, __LINE__,
10332 "S", "ERROR: unsupported address-type");
10339 - if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) ||
10341 + if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) ||
10342 (con->conf.is_ssl == 1 && srv->srvconf.port == 443))) {
10343 buffer_append_string(o, ":");
10344 buffer_append_long(o, srv->srvconf.port);
10345 @@ -190,41 +190,41 @@
10346 buffer_append_string(o, "?");
10347 buffer_append_string_buffer(o, con->uri.query);
10351 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(o));
10354 con->http_status = 301;
10355 con->file_finished = 1;
10364 buffer * strftime_cache_get(server *srv, time_t last_mod) {
10369 for (i = 0; i < FILE_CACHE_MAX; i++) {
10370 /* found cache-entry */
10371 if (srv->mtime_cache[i].mtime == last_mod) return srv->mtime_cache[i].str;
10374 /* found empty slot */
10375 if (srv->mtime_cache[i].mtime == 0) break;
10379 if (i == FILE_CACHE_MAX) {
10384 srv->mtime_cache[i].mtime = last_mod;
10385 buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
10386 tm = gmtime(&(srv->mtime_cache[i].mtime));
10387 - srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
10388 + srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
10389 srv->mtime_cache[i].str->size - 1,
10390 "%a, %d %b %Y %H:%M:%S GMT", tm);
10391 srv->mtime_cache[i].str->used++;
10394 return srv->mtime_cache[i].str;
10397 @@ -239,56 +239,60 @@
10398 * request. That is, if no entity tags match, then the server MUST NOT
10399 * return a 304 (Not Modified) response.
10403 /* last-modified handling */
10404 if (con->request.http_if_none_match) {
10405 if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
10406 - if (con->request.http_method == HTTP_METHOD_GET ||
10407 + if (con->request.http_method == HTTP_METHOD_GET ||
10408 con->request.http_method == HTTP_METHOD_HEAD) {
10411 /* check if etag + last-modified */
10412 if (con->request.http_if_modified_since) {
10417 if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
10418 used_len = strlen(con->request.http_if_modified_since);
10420 used_len = semicolon - con->request.http_if_modified_since;
10424 if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
10425 con->http_status = 304;
10426 return HANDLER_FINISHED;
10428 +#ifdef HAVE_STRPTIME
10429 char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
10430 + time_t t_header, t_file;
10433 - /* convert to timestamp */
10434 - if (used_len < sizeof(buf)) {
10435 - time_t t_header, t_file;
10438 - strncpy(buf, con->request.http_if_modified_since, used_len);
10439 - buf[used_len] = '\0';
10441 - strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10442 - t_header = mktime(&tm);
10444 - strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10445 - t_file = mktime(&tm);
10447 - if (t_file > t_header) {
10448 - con->http_status = 304;
10449 - return HANDLER_FINISHED;
10452 - log_error_write(srv, __FILE__, __LINE__, "ssdd",
10453 - "DEBUG: Last-Modified check failed as the received timestamp was too long:",
10454 + /* check if we can safely copy the string */
10455 + if (used_len >= sizeof(buf)) {
10456 + log_error_write(srv, __FILE__, __LINE__, "ssdd",
10457 + "DEBUG: Last-Modified check failed as the received timestamp was too long:",
10458 con->request.http_if_modified_since, used_len, sizeof(buf) - 1);
10461 con->http_status = 412;
10462 return HANDLER_FINISHED;
10466 + strncpy(buf, con->request.http_if_modified_since, used_len);
10467 + buf[used_len] = '\0';
10469 + strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10470 + t_header = mktime(&tm);
10472 + strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10473 + t_file = mktime(&tm);
10475 + if (t_file > t_header) return HANDLER_GO_ON;
10477 + con->http_status = 304;
10478 + return HANDLER_FINISHED;
10480 + return HANDLER_GO_ON;
10484 con->http_status = 304;
10485 @@ -302,16 +306,41 @@
10486 } else if (con->request.http_if_modified_since) {
10491 if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
10492 used_len = strlen(con->request.http_if_modified_since);
10494 used_len = semicolon - con->request.http_if_modified_since;
10498 if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
10499 con->http_status = 304;
10500 return HANDLER_FINISHED;
10502 +#ifdef HAVE_STRPTIME
10503 + char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
10504 + time_t t_header, t_file;
10507 + /* convert to timestamp */
10508 + if (used_len >= sizeof(buf)) return HANDLER_GO_ON;
10510 + strncpy(buf, con->request.http_if_modified_since, used_len);
10511 + buf[used_len] = '\0';
10513 + strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10514 + t_header = mktime(&tm);
10516 + strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10517 + t_file = mktime(&tm);
10519 + if (t_file > t_header) return HANDLER_GO_ON;
10521 + con->http_status = 304;
10522 + return HANDLER_FINISHED;
10524 + return HANDLER_GO_ON;
10529 --- ../lighttpd-1.4.11/src/http_auth.c 2006-02-01 13:02:52.000000000 +0200
10530 +++ lighttpd-1.4.12/src/http_auth.c 2006-07-18 13:03:40.000000000 +0300
10532 #include <string.h>
10535 -#include <unistd.h>
10538 #include "server.h"
10539 @@ -31,23 +30,14 @@
10540 #include "http_auth_digest.h"
10541 #include "stream.h"
10543 +#include "sys-strings.h"
10546 # include <openssl/md5.h>
10553 -#include <security/pam_appl.h>
10554 -#include <security/pam_misc.h>
10556 -static struct pam_conv conv = {
10562 handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
10564 static const char base64_pad = '=';
10565 @@ -75,25 +65,25 @@
10566 unsigned char *result;
10571 size_t in_len = strlen(in);
10574 buffer_prepare_copy(out, in_len);
10577 result = (unsigned char *)out->ptr;
10581 /* run through the whole string, converting as we go */
10582 for (i = 0; i < in_len; i++) {
10586 if (ch == '\0') break;
10589 if (ch == base64_pad) break;
10592 ch = base64_reverse_table[ch];
10593 if (ch < 0) continue;
10598 result[j] = ch << 2;
10599 @@ -125,168 +115,168 @@
10611 static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *username, buffer *realm, buffer *password) {
10615 if (!username->used|| !realm->used) return -1;
10618 if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
10623 if (buffer_is_empty(p->conf.auth_htdigest_userfile)) return -1;
10626 if (0 != stream_open(&f, p->conf.auth_htdigest_userfile)) {
10627 log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", p->conf.auth_htdigest_userfile, "failed:", strerror(errno));
10637 while (f_line - f.start != f.size) {
10638 char *f_user, *f_pwd, *e, *f_realm;
10639 size_t u_len, pwd_len, r_len;
10649 - * user:realm:md5(user:realm:password)
10651 + * user:realm:md5(user:realm:password)
10655 if (NULL == (f_realm = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
10656 - log_error_write(srv, __FILE__, __LINE__, "sbs",
10657 - "parsed error in", p->conf.auth_htdigest_userfile,
10658 + log_error_write(srv, __FILE__, __LINE__, "sbs",
10659 + "parsed error in", p->conf.auth_htdigest_userfile,
10660 "expected 'username:realm:hashed password'");
10670 if (NULL == (f_pwd = memchr(f_realm + 1, ':', f.size - (f_realm + 1 - f.start)))) {
10671 - log_error_write(srv, __FILE__, __LINE__, "sbs",
10672 - "parsed error in", p->conf.auth_plain_userfile,
10673 + log_error_write(srv, __FILE__, __LINE__, "sbs",
10674 + "parsed error in", p->conf.auth_plain_userfile,
10675 "expected 'username:realm:hashed password'");
10685 /* get pointers to the fields */
10686 - u_len = f_realm - f_user;
10687 + u_len = f_realm - f_user;
10689 r_len = f_pwd - f_realm;
10693 if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
10694 pwd_len = e - f_pwd;
10696 pwd_len = f.size - (f_pwd - f.start);
10700 if (username->used - 1 == u_len &&
10701 (realm->used - 1 == r_len) &&
10702 (0 == strncmp(username->ptr, f_user, u_len)) &&
10703 (0 == strncmp(realm->ptr, f_realm, r_len))) {
10707 buffer_copy_string_len(password, f_pwd, pwd_len);
10724 } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD ||
10725 p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
10731 auth_fn = (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) ? p->conf.auth_htpasswd_userfile : p->conf.auth_plain_userfile;
10734 if (buffer_is_empty(auth_fn)) return -1;
10737 if (0 != stream_open(&f, auth_fn)) {
10738 - log_error_write(srv, __FILE__, __LINE__, "sbss",
10739 + log_error_write(srv, __FILE__, __LINE__, "sbss",
10740 "opening plain-userfile", auth_fn, "failed:", strerror(errno));
10750 while (f_line - f.start != f.size) {
10751 char *f_user, *f_pwd, *e;
10752 size_t u_len, pwd_len;
10763 * user:crypted passwd
10767 if (NULL == (f_pwd = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
10768 - log_error_write(srv, __FILE__, __LINE__, "sbs",
10769 - "parsed error in", auth_fn,
10770 + log_error_write(srv, __FILE__, __LINE__, "sbs",
10771 + "parsed error in", auth_fn,
10772 "expected 'username:hashed password'");
10782 /* get pointers to the fields */
10783 - u_len = f_pwd - f_user;
10784 + u_len = f_pwd - f_user;
10788 if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
10789 pwd_len = e - f_pwd;
10791 pwd_len = f.size - (f_pwd - f.start);
10795 if (username->used - 1 == u_len &&
10796 (0 == strncmp(username->ptr, f_user, u_len))) {
10800 buffer_copy_string_len(password, f_pwd, pwd_len);
10817 } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
10827 @@ -296,7 +286,7 @@
10829 data_string *require;
10836 @@ -304,12 +294,12 @@
10837 /* search auth-directives for path */
10838 for (i = 0; i < p->conf.auth_require->used; i++) {
10839 if (p->conf.auth_require->data[i]->key->used == 0) continue;
10842 if (0 == strncmp(url, p->conf.auth_require->data[i]->key->ptr, p->conf.auth_require->data[i]->key->used - 1)) {
10848 if (i == p->conf.auth_require->used) {
10851 @@ -317,72 +307,72 @@
10852 req = ((data_array *)(p->conf.auth_require->data[i]))->value;
10854 require = (data_string *)array_get_element(req, "require");
10857 /* if we get here, the user we got a authed user */
10858 - if (0 == strcmp(require->value->ptr, "valid-user")) {
10859 + if (buffer_is_equal_string(require->value, CONST_STR_LEN("valid-user"))) {
10864 /* user=name1|group=name3|host=name4 */
10867 /* seperate the string by | */
10869 log_error_write(srv, __FILE__, __LINE__, "sb", "rules", require->value);
10874 username_len = username ? strlen(username) : 0;
10877 r = rules = require->value->ptr;
10882 const char *k, *v, *e;
10883 int k_len, v_len, r_len;
10886 e = strchr(r, '|');
10892 r_len = strlen(rules) - (r - rules);
10896 /* from r to r + r_len is a rule */
10899 if (0 == strncmp(r, "valid-user", r_len)) {
10900 - log_error_write(srv, __FILE__, __LINE__, "sb",
10901 + log_error_write(srv, __FILE__, __LINE__, "sb",
10902 "parsing the 'require' section in 'auth.require' failed: valid-user cannot be combined with other require rules",
10908 /* search for = in the rules */
10909 if (NULL == (eq = strchr(r, '='))) {
10910 - log_error_write(srv, __FILE__, __LINE__, "sb",
10911 - "parsing the 'require' section in 'auth.require' failed: a = is missing",
10912 + log_error_write(srv, __FILE__, __LINE__, "sb",
10913 + "parsing the 'require' section in 'auth.require' failed: a = is missing",
10919 /* = out of range */
10920 if (eq > r + r_len) {
10921 - log_error_write(srv, __FILE__, __LINE__, "sb",
10922 + log_error_write(srv, __FILE__, __LINE__, "sb",
10923 "parsing the 'require' section in 'auth.require' failed: = out of range",
10931 /* the part before the = is user|group|host */
10937 v_len = r_len - k_len - 1;
10941 if (0 == strncmp(k, "user", k_len)) {
10944 username_len == v_len &&
10945 0 == strncmp(username, v, v_len)) {
10947 @@ -404,19 +394,19 @@
10948 log_error_write(srv, __FILE__, __LINE__, "s", "unknown key");
10958 log_error_write(srv, __FILE__, __LINE__, "s", "nothing matched");
10969 * @param password password-string from the auth-backend
10970 * @param pw password-string from the client
10972 @@ -426,16 +416,16 @@
10975 if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
10980 - * user:realm:md5(user:realm:password)
10982 + * user:realm:md5(user:realm:password)
10992 MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1);
10993 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
10994 @@ -443,24 +433,24 @@
10995 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
10996 MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
10997 MD5_Final(HA1, &Md5Ctx);
11002 - if (0 == strcmp(password->ptr, a1)) {
11004 + if (buffer_is_equal_string(password, a1, strlen(a1))) {
11007 - } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
11009 + } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
11013 size_t salt_len = 0;
11019 * user:crypted password
11025 * CRYPT_STD_DES 2-character (Default)
11026 * CRYPT_EXT_DES 9-character
11027 @@ -478,7 +468,7 @@
11029 } else if (password->ptr[0] == '$' && password->ptr[2] == '$') {
11030 char *dollar = NULL;
11033 if (NULL == (dollar = strchr(password->ptr + 3, '$'))) {
11034 fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
11036 @@ -495,48 +485,21 @@
11037 strncpy(salt, password->ptr, salt_len);
11039 salt[salt_len] = '\0';
11042 crypted = crypt(pw, salt);
11044 - if (0 == strcmp(password->ptr, crypted)) {
11045 + if (buffer_is_equal_string(password, crypted, strlen(crypted))) {
11048 fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
11052 - } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11053 - if (0 == strcmp(password->ptr, pw)) {
11056 - } else if (p->conf.auth_backend == AUTH_BACKEND_PAM) {
11058 - pam_handle_t *pamh=NULL;
11061 - retval = pam_start("lighttpd", username->ptr, &conv, &pamh);
11063 - if (retval == PAM_SUCCESS)
11064 - retval = pam_authenticate(pamh, 0); /* is user really user? */
11066 - if (retval == PAM_SUCCESS)
11067 - retval = pam_acct_mgmt(pamh, 0); /* permitted access? */
11069 - /* This is where we have been authorized or not. */
11071 - if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */
11073 - log_error_write(srv, __FILE__, __LINE__, "s", "failed to release authenticator");
11076 - if (retval == PAM_SUCCESS) {
11077 - log_error_write(srv, __FILE__, __LINE__, "s", "Authenticated");
11080 + } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11081 + if (buffer_is_equal_string(password, pw, strlen(pw))) {
11084 - log_error_write(srv, __FILE__, __LINE__, "s", "Not Authenticated");
11087 - } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
11088 + } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
11091 LDAPMessage *lm, *first;
11092 @@ -544,45 +507,45 @@
11094 char *attrs[] = { LDAP_NO_ATTRS, NULL };
11098 /* for now we stay synchronous */
11103 * 1. connect anonymously (done in plugin init)
11104 * 2. get DN for uid = username
11105 * 3. auth against ldap server
11106 * 4. (optional) check a field
11116 * we have to protect us againt username which modifies out filter in
11121 for (i = 0; i < username->used - 1; i++) {
11122 char c = username->ptr[i];
11128 - log_error_write(srv, __FILE__, __LINE__, "sbd",
11130 + log_error_write(srv, __FILE__, __LINE__, "sbd",
11131 "ldap: invalid character (a-zA-Z0-9 allowed) in username:", username, i);
11144 buffer_copy_string_buffer(p->ldap_filter, p->conf.ldap_filter_pre);
11145 buffer_append_string_buffer(p->ldap_filter, username);
11146 buffer_append_string_buffer(p->ldap_filter, p->conf.ldap_filter_post);
11152 if (p->conf.ldap == NULL ||
11153 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))) {
11154 @@ -590,71 +553,71 @@
11156 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))) {
11158 - log_error_write(srv, __FILE__, __LINE__, "sssb",
11159 + log_error_write(srv, __FILE__, __LINE__, "sssb",
11160 "ldap:", ldap_err2string(ret), "filter:", p->ldap_filter);
11168 if (NULL == (first = ldap_first_entry(p->conf.ldap, lm))) {
11169 log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
11179 if (NULL == (dn = ldap_get_dn(p->conf.ldap, first))) {
11180 log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
11196 if (NULL == (ldap = ldap_init(p->conf.auth_ldap_hostname->ptr, LDAP_PORT))) {
11197 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
11202 ret = LDAP_VERSION3;
11203 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
11204 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
11207 ldap_unbind_s(ldap);
11214 if (p->conf.auth_ldap_starttls == 1) {
11215 if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(ldap, NULL, NULL))) {
11216 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
11219 ldap_unbind_s(ldap);
11228 if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(ldap, dn, pw))) {
11229 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
11232 ldap_unbind_s(ldap);
11240 ldap_unbind_s(ldap);
11243 /* everything worked, good, access granted */
11249 @@ -664,65 +627,65 @@
11250 int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
11251 buffer *username, *password;
11255 data_string *realm;
11258 realm = (data_string *)array_get_element(req, "realm");
11261 username = buffer_init();
11262 password = buffer_init();
11265 base64_decode(username, realm_str);
11268 /* r2 == user:password */
11269 if (NULL == (pw = strchr(username->ptr, ':'))) {
11270 buffer_free(username);
11273 log_error_write(srv, __FILE__, __LINE__, "sb", ": is missing in", username);
11283 username->used = pw - username->ptr;
11286 /* copy password to r1 */
11287 if (http_auth_get_password(srv, p, username, realm->value, password)) {
11288 buffer_free(username);
11289 buffer_free(password);
11292 log_error_write(srv, __FILE__, __LINE__, "s", "get_password failed");
11299 /* password doesn't match */
11300 if (http_auth_basic_password_compare(srv, p, req, username, realm->value, password, pw)) {
11301 log_error_write(srv, __FILE__, __LINE__, "sbb", "password doesn't match for", con->uri.path, username);
11304 buffer_free(username);
11305 buffer_free(password);
11312 /* value is our allow-rules */
11313 if (http_auth_match_rules(srv, p, url->ptr, username->ptr, NULL, NULL)) {
11314 buffer_free(username);
11315 buffer_free(password);
11318 log_error_write(srv, __FILE__, __LINE__, "s", "rules didn't match");
11325 /* remember the username */
11326 buffer_copy_string_buffer(p->auth_user, username);
11329 buffer_free(username);
11330 buffer_free(password);
11336 @@ -735,7 +698,7 @@
11337 int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
11345 @@ -745,18 +708,18 @@
11352 const char *m = NULL;
11354 buffer *password, *b, *username_buf, *realm_buf;
11365 /* init pointers */
11367 @@ -771,11 +734,11 @@
11370 { S("response=") },
11378 dkv[0].ptr = &username;
11379 dkv[1].ptr = &realm;
11380 dkv[2].ptr = &nonce;
11381 @@ -786,24 +749,24 @@
11383 dkv[8].ptr = &respons;
11390 for (i = 0; dkv[i].key; i++) {
11391 *(dkv[i].ptr) = NULL;
11397 if (p->conf.auth_backend != AUTH_BACKEND_HTDIGEST &&
11398 p->conf.auth_backend != AUTH_BACKEND_PLAIN) {
11399 - log_error_write(srv, __FILE__, __LINE__, "s",
11400 + log_error_write(srv, __FILE__, __LINE__, "s",
11401 "digest: unsupported backend (only htdigest or plain)");
11408 b = buffer_init_string(realm_str);
11411 /* parse credentials from client */
11412 for (c = b->ptr; *c; c++) {
11413 /* skip whitespaces */
11414 @@ -812,18 +775,18 @@
11416 for (i = 0; dkv[i].key; i++) {
11417 if ((0 == strncmp(c, dkv[i].key, dkv[i].key_len))) {
11418 - if ((c[dkv[i].key_len] == '"') &&
11419 + if ((c[dkv[i].key_len] == '"') &&
11420 (NULL != (e = strchr(c + dkv[i].key_len + 1, '"')))) {
11421 /* value with "..." */
11422 *(dkv[i].ptr) = c + dkv[i].key_len + 1;
11427 } else if (NULL != (e = strchr(c + dkv[i].key_len, ','))) {
11428 /* value without "...", terminated by ',' */
11429 *(dkv[i].ptr) = c + dkv[i].key_len;
11435 /* value without "...", terminated by EOL */
11436 @@ -833,7 +796,7 @@
11442 if (p->conf.auth_debug > 1) {
11443 log_error_write(srv, __FILE__, __LINE__, "ss", "username", username);
11444 log_error_write(srv, __FILE__, __LINE__, "ss", "realm", realm);
11445 @@ -845,22 +808,22 @@
11446 log_error_write(srv, __FILE__, __LINE__, "ss", "nc", nc);
11447 log_error_write(srv, __FILE__, __LINE__, "ss", "response", respons);
11451 /* check if everything is transmitted */
11457 (qop && (!nc || !cnonce)) ||
11459 /* missing field */
11461 - log_error_write(srv, __FILE__, __LINE__, "s",
11463 + log_error_write(srv, __FILE__, __LINE__, "s",
11464 "digest: missing field");
11468 - m = get_http_method_name(con->request.http_method);
11469 + m = get_http_method_name(con->request.http_method);
11471 /* password-string == HA1 */
11472 password = buffer_init();
11473 @@ -873,10 +836,10 @@
11474 buffer_free(realm_buf);
11479 buffer_free(username_buf);
11480 buffer_free(realm_buf);
11483 if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11484 /* generate password from plain-text */
11486 @@ -890,16 +853,16 @@
11488 /* transform the 32-byte-hex-md5 to a 16-byte-md5 */
11489 for (i = 0; i < HASHLEN; i++) {
11490 - HA1[i] = hex2int(password->ptr[i*2]) << 4;
11491 - HA1[i] |= hex2int(password->ptr[i*2+1]);
11492 + HA1[i] = hex2int(password->ptr[i*2]) << 4;
11493 + HA1[i] |= hex2int(password->ptr[i*2+1]);
11496 /* we already check that above */
11501 buffer_free(password);
11505 strcasecmp(algorithm, "md5-sess") == 0) {
11507 @@ -910,9 +873,9 @@
11508 MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
11509 MD5_Final(HA1, &Md5Ctx);
11516 /* calculate H(A2) */
11518 MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m));
11519 @@ -924,7 +887,7 @@
11521 MD5_Final(HA2, &Md5Ctx);
11522 CvtHex(HA2, HA2Hex);
11525 /* calculate response */
11527 MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
11528 @@ -942,39 +905,39 @@
11529 MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
11530 MD5_Final(RespHash, &Md5Ctx);
11531 CvtHex(RespHash, a2);
11534 if (0 != strcmp(a2, respons)) {
11535 /* digest not ok */
11538 if (p->conf.auth_debug) {
11539 - log_error_write(srv, __FILE__, __LINE__, "sss",
11540 + log_error_write(srv, __FILE__, __LINE__, "sss",
11541 "digest: digest mismatch", a2, respons);
11544 - log_error_write(srv, __FILE__, __LINE__, "sss",
11546 + log_error_write(srv, __FILE__, __LINE__, "sss",
11547 "digest: auth failed for", username, "wrong password");
11555 /* value is our allow-rules */
11556 if (http_auth_match_rules(srv, p, url->ptr, username, NULL, NULL)) {
11559 - log_error_write(srv, __FILE__, __LINE__, "s",
11561 + log_error_write(srv, __FILE__, __LINE__, "s",
11562 "digest: rules did match");
11569 /* remember the username */
11570 buffer_copy_string(p->auth_user, username);
11576 if (p->conf.auth_debug) {
11577 - log_error_write(srv, __FILE__, __LINE__, "s",
11578 + log_error_write(srv, __FILE__, __LINE__, "s",
11579 "digest: auth ok");
11582 @@ -985,23 +948,23 @@
11590 /* generate shared-secret */
11592 MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1);
11593 MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
11596 /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
11597 ltostr(hh, srv->cur_ts);
11598 MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
11599 ltostr(hh, rand());
11600 MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
11603 MD5_Final(h, &Md5Ctx);
11611 --- ../lighttpd-1.4.11/src/http_auth.h 2005-08-14 17:12:31.000000000 +0300
11612 +++ lighttpd-1.4.12/src/http_auth.h 2006-07-16 00:26:04.000000000 +0300
11617 -typedef enum { AUTH_BACKEND_UNSET, AUTH_BACKEND_PLAIN,
11618 - AUTH_BACKEND_LDAP, AUTH_BACKEND_HTPASSWD,
11619 - AUTH_BACKEND_HTDIGEST, AUTH_BACKEND_PAM } auth_backend_t;
11621 + AUTH_BACKEND_UNSET,
11622 + AUTH_BACKEND_PLAIN,
11623 + AUTH_BACKEND_LDAP,
11624 + AUTH_BACKEND_HTPASSWD,
11625 + AUTH_BACKEND_HTDIGEST
11630 array *auth_require;
11633 buffer *auth_plain_groupfile;
11634 buffer *auth_plain_userfile;
11637 buffer *auth_htdigest_userfile;
11638 buffer *auth_htpasswd_userfile;
11641 buffer *auth_backend_conf;
11644 buffer *auth_ldap_hostname;
11645 buffer *auth_ldap_basedn;
11646 buffer *auth_ldap_binddn;
11647 @@ -32,15 +36,15 @@
11648 buffer *auth_ldap_filter;
11649 buffer *auth_ldap_cafile;
11650 unsigned short auth_ldap_starttls;
11653 unsigned short auth_debug;
11657 auth_backend_t auth_backend;
11664 buffer *ldap_filter_pre;
11665 buffer *ldap_filter_post;
11667 @@ -49,15 +53,15 @@
11676 buffer *ldap_filter;
11680 mod_auth_plugin_config **config_storage;
11683 mod_auth_plugin_config conf; /* this is only used as long as no handler_ctx is setup */
11684 } mod_auth_plugin_data;
11686 --- ../lighttpd-1.4.11/src/http_auth_digest.h 2006-01-05 00:54:01.000000000 +0200
11687 +++ lighttpd-1.4.12/src/http_auth_digest.h 2006-07-16 00:26:04.000000000 +0300
11697 --- ../lighttpd-1.4.11/src/http_chunk.c 2005-08-11 01:26:50.000000000 +0300
11698 +++ lighttpd-1.4.12/src/http_chunk.c 2006-07-16 00:26:04.000000000 +0300
11701 * the HTTP chunk-API
11708 #include <sys/types.h>
11711 #include <stdlib.h>
11713 -#include <unistd.h>
11717 @@ -23,19 +22,19 @@
11718 static int http_chunk_append_len(server *srv, connection *con, size_t len) {
11719 size_t i, olen = len, j;
11723 b = srv->tmp_chunk_len;
11727 buffer_copy_string(b, "0");
11729 for (i = 0; i < 8 && len; i++) {
11734 /* i is the number of hex digits we have */
11735 buffer_prepare_copy(b, i + 1);
11738 for (j = i-1, len = olen; j+1 > 0; j--) {
11739 b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
11741 @@ -43,61 +42,61 @@
11743 b->ptr[b->used++] = '\0';
11747 buffer_append_string(b, "\r\n");
11748 chunkqueue_append_buffer(con->write_queue, b);
11755 int http_chunk_append_file(server *srv, connection *con, buffer *fn, off_t offset, off_t len) {
11759 if (!con) return -1;
11762 cq = con->write_queue;
11765 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11766 http_chunk_append_len(srv, con, len);
11770 chunkqueue_append_file(cq, fn, offset, len);
11773 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && len > 0) {
11774 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11781 int http_chunk_append_buffer(server *srv, connection *con, buffer *mem) {
11785 if (!con) return -1;
11788 cq = con->write_queue;
11791 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11792 http_chunk_append_len(srv, con, mem->used - 1);
11796 chunkqueue_append_buffer(cq, mem);
11799 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && mem->used > 0) {
11800 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11807 int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len) {
11811 if (!con) return -1;
11814 cq = con->write_queue;
11818 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11819 http_chunk_append_len(srv, con, 0);
11820 @@ -107,17 +106,17 @@
11826 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11827 http_chunk_append_len(srv, con, len - 1);
11831 chunkqueue_append_mem(cq, mem, len);
11834 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11835 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11842 @@ -125,9 +124,9 @@
11843 off_t http_chunkqueue_length(server *srv, connection *con) {
11845 log_error_write(srv, __FILE__, __LINE__, "s", "connection is NULL!!");
11852 return chunkqueue_length(con->write_queue);
11854 --- ../lighttpd-1.4.11/src/http_resp.c 1970-01-01 03:00:00.000000000 +0300
11855 +++ lighttpd-1.4.12/src/http_resp.c 2006-07-18 13:03:40.000000000 +0300
11857 +#include <string.h>
11858 +#include <stdlib.h>
11859 +#include <stdio.h>
11860 +#include <assert.h>
11863 +#include "http_resp.h"
11864 +#include "http_resp_parser.h"
11866 +/* declare prototypes for the parser */
11867 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t));
11868 +void http_resp_parserFree(void *p, void (*freeProc)(void*));
11869 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt);
11870 +void http_resp_parser(void *, int, buffer *, http_resp_ctx_t *);
11875 + chunk *c; /* current chunk in the chunkqueue */
11876 + size_t offset; /* current offset in current chunk */
11879 + size_t lookup_offset;
11882 + int is_statusline;
11883 +} http_resp_tokenizer_t;
11885 +http_resp *http_response_init(void) {
11886 + http_resp *resp = calloc(1, sizeof(*resp));
11888 + resp->reason = buffer_init();
11889 + resp->headers = array_init();
11894 +void http_response_reset(http_resp *resp) {
11895 + if (!resp) return;
11897 + buffer_reset(resp->reason);
11898 + array_reset(resp->headers);
11902 +void http_response_free(http_resp *resp) {
11903 + if (!resp) return;
11905 + buffer_free(resp->reason);
11906 + array_free(resp->headers);
11911 +static int http_resp_get_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
11912 + if (t->offset == t->c->mem->used - 1) {
11913 + /* end of chunk, open next chunk */
11915 + if (!t->c->next) return -1;
11917 + t->c = t->c->next;
11921 + *c = t->c->mem->ptr[t->offset++];
11923 + t->lookup_offset = t->offset;
11924 + t->lookup_c = t->c;
11927 + fprintf(stderr, "%s.%d: get: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->offset - 1);
11933 +static int http_resp_lookup_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
11934 + if (t->lookup_offset == t->lookup_c->mem->used - 1) {
11935 + /* end of chunk, open next chunk */
11937 + if (!t->lookup_c->next) return -1;
11939 + t->lookup_c = t->lookup_c->next;
11940 + t->lookup_offset = 0;
11943 + *c = t->lookup_c->mem->ptr[t->lookup_offset++];
11945 + fprintf(stderr, "%s.%d: lookup: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->lookup_offset - 1);
11952 +static int http_resp_tokenizer(
11953 + http_resp_tokenizer_t *t,
11960 + /* push the token to the parser */
11962 + while (tid == 0 && 0 == http_resp_get_next_char(t, &c)) {
11976 + if (0 != http_resp_lookup_next_char(t, &c)) return -1;
11981 + t->c = t->lookup_c;
11982 + t->offset = t->lookup_offset;
11984 + t->is_statusline = 0;
11987 + fprintf(stderr, "%s.%d: CR with out LF\r\n", __FILE__, __LINE__);
11994 + t->is_statusline = 0;
11999 + while (c >= 32 && c != 127 && c != 255) {
12000 + if (t->is_statusline) {
12001 + if (c == ':') { t->is_statusline = 0; break; } /* this is not a status line by a real header */
12002 + if (c == 32) break; /* the space is a splitter in the statusline */
12005 + if (c == ':') break; /* the : is the splitter between key and value */
12008 + if (0 != http_resp_lookup_next_char(t, &c)) return -1;
12011 + if (t->c == t->lookup_c &&
12012 + t->offset == t->lookup_offset + 1) {
12014 + fprintf(stderr, "%s.%d: invalid char in string\n", __FILE__, __LINE__);
12020 + /* the lookup points to the first invalid char */
12021 + t->lookup_offset--;
12023 + /* no overlapping string */
12024 + if (t->c == t->lookup_c) {
12025 + buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->lookup_offset - t->offset + 1);
12027 + /* first chunk */
12028 + buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->c->mem->used - t->offset);
12030 + /* chunks in the middle */
12031 + for (t->c = t->c->next; t->c != t->lookup_c; t->c = t->c->next) {
12032 + buffer_append_string_buffer(token, t->c->mem);
12033 + t->offset = t->c->mem->used - 1;
12037 + buffer_append_string_len(token, t->c->mem->ptr, t->lookup_offset);
12040 + t->offset = t->lookup_offset;
12055 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *resp) {
12056 + http_resp_tokenizer_t t;
12057 + void *pParser = NULL;
12058 + int token_id = 0;
12059 + buffer *token = NULL;
12060 + http_resp_ctx_t context;
12061 + parse_status_t ret = PARSE_UNSET;
12062 + int last_token_id = 0;
12066 + t.offset = t.c->offset;
12068 + t.is_statusline = 1;
12071 + context.errmsg = buffer_init();
12072 + context.resp = resp;
12074 + pParser = http_resp_parserAlloc( malloc );
12075 + token = buffer_init();
12077 + http_resp_parserTrace(stderr, "http-response: ");
12080 + while((1 == http_resp_tokenizer(&t, &token_id, token)) && context.ok) {
12081 + http_resp_parser(pParser, token_id, token, &context);
12083 + token = buffer_init();
12085 + /* CRLF CRLF ... the header end sequence */
12086 + if (last_token_id == TK_CRLF &&
12087 + token_id == TK_CRLF) break;
12089 + last_token_id = token_id;
12092 + /* oops, the parser failed */
12093 + if (context.ok == 0) {
12094 + ret = PARSE_ERROR;
12096 + if (!buffer_is_empty(context.errmsg)) {
12097 + TRACE("parsing failed: %s", BUF_STR(context.errmsg));
12099 + TRACE("%s", "parsing failed ...");
12103 + http_resp_parser(pParser, 0, token, &context);
12104 + http_resp_parserFree(pParser, free);
12106 + if (context.ok == 0) {
12107 + /* we are missing the some tokens */
12109 + if (!buffer_is_empty(context.errmsg)) {
12110 + TRACE("parsing failed: %s", BUF_STR(context.errmsg));
12113 + if (ret == PARSE_UNSET) {
12114 + ret = buffer_is_empty(context.errmsg) ? PARSE_NEED_MORE : PARSE_ERROR;
12119 + for (c = cq->first; c != t.c; c = c->next) {
12120 + c->offset = c->mem->used - 1;
12123 + c->offset = t.offset;
12125 + ret = PARSE_SUCCESS;
12128 + buffer_free(token);
12129 + buffer_free(context.errmsg);
12134 --- ../lighttpd-1.4.11/src/http_resp.h 1970-01-01 03:00:00.000000000 +0300
12135 +++ lighttpd-1.4.12/src/http_resp.h 2006-07-16 00:26:04.000000000 +0300
12137 +#ifndef _HTTP_RESP_H_
12138 +#define _HTTP_RESP_H_
12140 +#include "array.h"
12141 +#include "chunk.h"
12151 + int protocol; /* http/1.0, http/1.1 */
12152 + int status; /* e.g. 200 */
12153 + buffer *reason; /* e.g. Ok */
12162 +} http_resp_ctx_t;
12164 +http_resp *http_response_init(void);
12165 +void http_response_free(http_resp *resp);
12166 +void http_response_reset(http_resp *resp);
12168 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *http_response);
12171 --- ../lighttpd-1.4.11/src/http_resp_parser.c 1970-01-01 03:00:00.000000000 +0300
12172 +++ lighttpd-1.4.12/src/http_resp_parser.c 2006-07-18 13:03:52.000000000 +0300
12174 +/* Driver template for the LEMON parser generator.
12175 +** The author disclaims copyright to this source code.
12177 +/* First off, code is include which follows the "include" declaration
12178 +** in the input file. */
12179 +#include <stdio.h>
12180 +#line 6 "./http_resp_parser.y"
12182 +#include <assert.h>
12183 +#include <string.h>
12184 +#include "http_resp.h"
12185 +#include "keyvalue.h"
12186 +#include "array.h"
12189 +#line 17 "http_resp_parser.c"
12190 +/* Next is all token values, in a form suitable for use by makeheaders.
12191 +** This section will be null unless lemon is run with the -m switch.
12194 +** These constants (all generated automatically by the parser generator)
12195 +** specify the various kinds of tokens (terminals) that the parser
12198 +** Each symbol here is a terminal symbol in the grammar.
12200 +/* Make sure the INTERFACE macro is defined.
12203 +# define INTERFACE 1
12205 +/* The next thing included is series of defines which control
12206 +** various aspects of the generated parser.
12207 +** YYCODETYPE is the data type used for storing terminal
12208 +** and nonterminal numbers. "unsigned char" is
12209 +** used if there are fewer than 250 terminals
12210 +** and nonterminals. "int" is used otherwise.
12211 +** YYNOCODE is a number of type YYCODETYPE which corresponds
12212 +** to no legal terminal or nonterminal number. This
12213 +** number is used to fill in empty slots of the hash
12215 +** YYFALLBACK If defined, this indicates that one or more tokens
12216 +** have fall-back values which should be used if the
12217 +** original value of the token will not parse.
12218 +** YYACTIONTYPE is the data type used for storing terminal
12219 +** and nonterminal numbers. "unsigned char" is
12220 +** used if there are fewer than 250 rules and
12221 +** states combined. "int" is used otherwise.
12222 +** http_resp_parserTOKENTYPE is the data type used for minor tokens given
12223 +** directly to the parser from the tokenizer.
12224 +** YYMINORTYPE is the data type used for all minor tokens.
12225 +** This is typically a union of many types, one of
12226 +** which is http_resp_parserTOKENTYPE. The entry in the union
12227 +** for base tokens is called "yy0".
12228 +** YYSTACKDEPTH is the maximum depth of the parser's stack.
12229 +** http_resp_parserARG_SDECL A static variable declaration for the %extra_argument
12230 +** http_resp_parserARG_PDECL A parameter declaration for the %extra_argument
12231 +** http_resp_parserARG_STORE Code to store %extra_argument into yypParser
12232 +** http_resp_parserARG_FETCH Code to extract %extra_argument from yypParser
12233 +** YYNSTATE the combined number of states.
12234 +** YYNRULE the number of rules in the grammar
12235 +** YYERRORSYMBOL is the code number of the error symbol. If not
12236 +** defined, then do no error processing.
12239 +#define YYCODETYPE unsigned char
12240 +#define YYNOCODE 12
12241 +#define YYACTIONTYPE unsigned char
12242 +#define http_resp_parserTOKENTYPE buffer *
12244 + http_resp_parserTOKENTYPE yy0;
12246 + data_string * yy9;
12251 +#define YYSTACKDEPTH 100
12252 +#define http_resp_parserARG_SDECL http_resp_ctx_t *ctx;
12253 +#define http_resp_parserARG_PDECL ,http_resp_ctx_t *ctx
12254 +#define http_resp_parserARG_FETCH http_resp_ctx_t *ctx = yypParser->ctx
12255 +#define http_resp_parserARG_STORE yypParser->ctx = ctx
12256 +#define YYNSTATE 19
12258 +#define YYERRORSYMBOL 4
12259 +#define YYERRSYMDT yy23
12260 +#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
12261 +#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
12262 +#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
12264 +/* Next are that tables used to determine what action to take based on the
12265 +** current state and lookahead token. These tables are used to implement
12266 +** functions that take a state number and lookahead value and return an
12267 +** action integer.
12269 +** Suppose the action integer is N. Then the action is determined as
12272 +** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
12273 +** token onto the stack and goto state N.
12275 +** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
12277 +** N == YYNSTATE+YYNRULE A syntax error has occurred.
12279 +** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
12281 +** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
12282 +** slots in the yy_action[] table.
12284 +** The action table is constructed as a single large table named yy_action[].
12285 +** Given state S and lookahead X, the action is computed as
12287 +** yy_action[ yy_shift_ofst[S] + X ]
12289 +** If the index value yy_shift_ofst[S]+X is out of range or if the value
12290 +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
12291 +** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
12292 +** and that yy_default[S] should be used instead.
12294 +** The formula above is for computing the action when the lookahead is
12295 +** a terminal symbol. If the lookahead is a non-terminal (as occurs after
12296 +** a reduce action) then the yy_reduce_ofst[] array is used in place of
12297 +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
12298 +** YY_SHIFT_USE_DFLT.
12300 +** The following are the tables generated in this section:
12302 +** yy_action[] A single table containing all actions.
12303 +** yy_lookahead[] A table containing the lookahead for each entry in
12304 +** yy_action. Used to detect hash collisions.
12305 +** yy_shift_ofst[] For each state, the offset into yy_action for
12306 +** shifting terminals.
12307 +** yy_reduce_ofst[] For each state, the offset into yy_action for
12308 +** shifting non-terminals after a reduce.
12309 +** yy_default[] Default action for each state.
12311 +static YYACTIONTYPE yy_action[] = {
12312 + /* 0 */ 8, 29, 18, 1, 14, 2, 4, 11, 15, 12,
12313 + /* 10 */ 14, 13, 4, 21, 5, 19, 3, 5, 6, 7,
12314 + /* 20 */ 9, 17, 16, 4, 20, 22, 22, 10,
12316 +static YYCODETYPE yy_lookahead[] = {
12317 + /* 0 */ 5, 6, 2, 8, 9, 1, 2, 1, 2, 8,
12318 + /* 10 */ 9, 1, 2, 2, 3, 0, 9, 3, 2, 1,
12319 + /* 20 */ 7, 2, 2, 2, 0, 2, 11, 10,
12321 +#define YY_SHIFT_USE_DFLT (-1)
12322 +static signed char yy_shift_ofst[] = {
12323 + /* 0 */ 0, 4, 15, -1, 14, 16, 18, -1, 19, 20,
12324 + /* 10 */ 6, 21, 10, 24, -1, -1, -1, 23, 11,
12326 +#define YY_REDUCE_USE_DFLT (-6)
12327 +static signed char yy_reduce_ofst[] = {
12328 + /* 0 */ -5, 7, -6, -6, -6, -6, -6, -6, 13, 17,
12329 + /* 10 */ -6, 1, 7, -6, -6, -6, -6, -6, -6,
12331 +static YYACTIONTYPE yy_default[] = {
12332 + /* 0 */ 28, 28, 28, 25, 28, 28, 28, 27, 28, 28,
12333 + /* 10 */ 28, 28, 28, 28, 26, 24, 23, 28, 28,
12335 +#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
12337 +/* The next table maps tokens into fallback tokens. If a construct
12338 +** like the following:
12340 +** %fallback ID X Y Z.
12342 +** appears in the grammer, then ID becomes a fallback token for X, Y,
12343 +** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
12344 +** but it does not parse, the type of the token is changed to ID and
12345 +** the parse is retried before an error is thrown.
12348 +static const YYCODETYPE yyFallback[] = {
12350 +#endif /* YYFALLBACK */
12352 +/* The following structure represents a single element of the
12353 +** parser's stack. Information stored includes:
12355 +** + The state number for the parser at this level of the stack.
12357 +** + The value of the token stored at this level of the stack.
12358 +** (In other words, the "major" token.)
12360 +** + The semantic value stored at this level of the stack. This is
12361 +** the information used by the action routines in the grammar.
12362 +** It is sometimes called the "minor" token.
12364 +struct yyStackEntry {
12365 + int stateno; /* The state-number */
12366 + int major; /* The major token value. This is the code
12367 + ** number for the token at this stack level */
12368 + YYMINORTYPE minor; /* The user-supplied minor token value. This
12369 + ** is the value of the token */
12371 +typedef struct yyStackEntry yyStackEntry;
12373 +/* The state of the parser is completely contained in an instance of
12374 +** the following structure */
12376 + int yyidx; /* Index of top element in stack */
12377 + int yyerrcnt; /* Shifts left before out of the error */
12378 + http_resp_parserARG_SDECL /* A place to hold %extra_argument */
12379 + yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
12381 +typedef struct yyParser yyParser;
12384 +#include <stdio.h>
12385 +static FILE *yyTraceFILE = 0;
12386 +static char *yyTracePrompt = 0;
12387 +#endif /* NDEBUG */
12391 +** Turn parser tracing on by giving a stream to which to write the trace
12392 +** and a prompt to preface each trace message. Tracing is turned off
12393 +** by making either argument NULL
12397 +** <li> A FILE* to which trace output should be written.
12398 +** If NULL, then tracing is turned off.
12399 +** <li> A prefix string written at the beginning of every
12400 +** line of trace output. If NULL, then tracing is
12407 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt){
12408 + yyTraceFILE = TraceFILE;
12409 + yyTracePrompt = zTracePrompt;
12410 + if( yyTraceFILE==0 ) yyTracePrompt = 0;
12411 + else if( yyTracePrompt==0 ) yyTraceFILE = 0;
12413 +#endif /* NDEBUG */
12416 +/* For tracing shifts, the names of all terminals and nonterminals
12417 +** are required. The following table supplies these names */
12418 +static const char *yyTokenName[] = {
12419 + "$", "CRLF", "STRING", "COLON",
12420 + "error", "protocol", "response_hdr", "number",
12421 + "headers", "header", "reason",
12423 +#endif /* NDEBUG */
12426 +/* For tracing reduce actions, the names of all rules are required.
12428 +static const char *yyRuleName[] = {
12429 + /* 0 */ "response_hdr ::= headers CRLF",
12430 + /* 1 */ "response_hdr ::= protocol number reason CRLF headers CRLF",
12431 + /* 2 */ "protocol ::= STRING",
12432 + /* 3 */ "number ::= STRING",
12433 + /* 4 */ "reason ::= STRING",
12434 + /* 5 */ "reason ::= reason STRING",
12435 + /* 6 */ "headers ::= headers header",
12436 + /* 7 */ "headers ::= header",
12437 + /* 8 */ "header ::= STRING COLON STRING CRLF",
12439 +#endif /* NDEBUG */
12442 +** This function returns the symbolic name associated with a token
12445 +const char *http_resp_parserTokenName(int tokenType){
12447 + if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
12448 + return yyTokenName[tokenType];
12450 + return "Unknown";
12458 +** This function allocates a new parser.
12459 +** The only argument is a pointer to a function which works like
12463 +** A pointer to the function used to allocate memory.
12466 +** A pointer to a parser. This pointer is used in subsequent calls
12467 +** to http_resp_parser and http_resp_parserFree.
12469 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t)){
12470 + yyParser *pParser;
12471 + pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
12473 + pParser->yyidx = -1;
12478 +/* The following function deletes the value associated with a
12479 +** symbol. The symbol can be either a terminal or nonterminal.
12480 +** "yymajor" is the symbol code, and "yypminor" is a pointer to
12483 +static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
12484 + switch( yymajor ){
12485 + /* Here is inserted the actions which take place when a
12486 + ** terminal or non-terminal is destroyed. This can happen
12487 + ** when the symbol is popped from the stack during a
12488 + ** reduce or during error processing or when a parser is
12489 + ** being destroyed before it is finished parsing.
12491 + ** Note: during a reduce, the only symbols destroyed are those
12492 + ** which appear on the RHS of the rule, but which are not used
12493 + ** inside the C code.
12498 +#line 25 "./http_resp_parser.y"
12499 +{ buffer_free((yypminor->yy0)); }
12500 +#line 327 "http_resp_parser.c"
12503 +#line 24 "./http_resp_parser.y"
12504 +{ buffer_free((yypminor->yy0)); }
12505 +#line 332 "http_resp_parser.c"
12507 + default: break; /* If no destructor action specified: do nothing */
12512 +** Pop the parser's stack once.
12514 +** If there is a destructor routine associated with the token which
12515 +** is popped from the stack, then call it.
12517 +** Return the major token number for the symbol popped.
12519 +static int yy_pop_parser_stack(yyParser *pParser){
12520 + YYCODETYPE yymajor;
12521 + yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
12523 + if( pParser->yyidx<0 ) return 0;
12525 + if( yyTraceFILE && pParser->yyidx>=0 ){
12526 + fprintf(yyTraceFILE,"%sPopping %s\n",
12528 + yyTokenName[yytos->major]);
12531 + yymajor = yytos->major;
12532 + yy_destructor( yymajor, &yytos->minor);
12533 + pParser->yyidx--;
12538 +** Deallocate and destroy a parser. Destructors are all called for
12539 +** all stack elements before shutting the parser down.
12543 +** <li> A pointer to the parser. This should be a pointer
12544 +** obtained from http_resp_parserAlloc.
12545 +** <li> A pointer to a function used to reclaim memory obtained
12549 +void http_resp_parserFree(
12550 + void *p, /* The parser to be deleted */
12551 + void (*freeProc)(void*) /* Function used to reclaim memory */
12553 + yyParser *pParser = (yyParser*)p;
12554 + if( pParser==0 ) return;
12555 + while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
12556 + (*freeProc)((void*)pParser);
12560 +** Find the appropriate action for a parser given the terminal
12561 +** look-ahead token iLookAhead.
12563 +** If the look-ahead token is YYNOCODE, then check to see if the action is
12564 +** independent of the look-ahead. If it is, return the action, otherwise
12565 +** return YY_NO_ACTION.
12567 +static int yy_find_shift_action(
12568 + yyParser *pParser, /* The parser */
12569 + int iLookAhead /* The look-ahead token */
12572 + int stateno = pParser->yystack[pParser->yyidx].stateno;
12574 + /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
12575 + i = yy_shift_ofst[stateno];
12576 + if( i==YY_SHIFT_USE_DFLT ){
12577 + return yy_default[stateno];
12579 + if( iLookAhead==YYNOCODE ){
12580 + return YY_NO_ACTION;
12583 + if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
12585 + int iFallback; /* Fallback token */
12586 + if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
12587 + && (iFallback = yyFallback[iLookAhead])!=0 ){
12589 + if( yyTraceFILE ){
12590 + fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
12591 + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
12594 + return yy_find_shift_action(pParser, iFallback);
12597 + return yy_default[stateno];
12599 + return yy_action[i];
12604 +** Find the appropriate action for a parser given the non-terminal
12605 +** look-ahead token iLookAhead.
12607 +** If the look-ahead token is YYNOCODE, then check to see if the action is
12608 +** independent of the look-ahead. If it is, return the action, otherwise
12609 +** return YY_NO_ACTION.
12611 +static int yy_find_reduce_action(
12612 + yyParser *pParser, /* The parser */
12613 + int iLookAhead /* The look-ahead token */
12616 + int stateno = pParser->yystack[pParser->yyidx].stateno;
12618 + i = yy_reduce_ofst[stateno];
12619 + if( i==YY_REDUCE_USE_DFLT ){
12620 + return yy_default[stateno];
12622 + if( iLookAhead==YYNOCODE ){
12623 + return YY_NO_ACTION;
12626 + if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
12627 + return yy_default[stateno];
12629 + return yy_action[i];
12634 +** Perform a shift action.
12636 +static void yy_shift(
12637 + yyParser *yypParser, /* The parser to be shifted */
12638 + int yyNewState, /* The new state to shift in */
12639 + int yyMajor, /* The major token to shift in */
12640 + YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */
12642 + yyStackEntry *yytos;
12643 + yypParser->yyidx++;
12644 + if( yypParser->yyidx>=YYSTACKDEPTH ){
12645 + http_resp_parserARG_FETCH;
12646 + yypParser->yyidx--;
12648 + if( yyTraceFILE ){
12649 + fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
12652 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12653 + /* Here code is inserted which will execute if the parser
12654 + ** stack every overflows */
12655 + http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument var */
12658 + yytos = &yypParser->yystack[yypParser->yyidx];
12659 + yytos->stateno = yyNewState;
12660 + yytos->major = yyMajor;
12661 + yytos->minor = *yypMinor;
12663 + if( yyTraceFILE && yypParser->yyidx>0 ){
12665 + fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
12666 + fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
12667 + for(i=1; i<=yypParser->yyidx; i++)
12668 + fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
12669 + fprintf(yyTraceFILE,"\n");
12674 +/* The following table contains information about every rule that
12675 +** is used during the reduce.
12678 + YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
12679 + unsigned char nrhs; /* Number of right-hand side symbols in the rule */
12680 +} yyRuleInfo[] = {
12692 +static void yy_accept(yyParser*); /* Forward Declaration */
12695 +** Perform a reduce action and the shift that must immediately
12696 +** follow the reduce.
12698 +static void yy_reduce(
12699 + yyParser *yypParser, /* The parser */
12700 + int yyruleno /* Number of the rule by which to reduce */
12702 + int yygoto; /* The next state */
12703 + int yyact; /* The next action */
12704 + YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
12705 + yyStackEntry *yymsp; /* The top of the parser's stack */
12706 + int yysize; /* Amount to pop the stack */
12707 + http_resp_parserARG_FETCH;
12708 + yymsp = &yypParser->yystack[yypParser->yyidx];
12710 + if( yyTraceFILE && yyruleno>=0
12711 + && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
12712 + fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
12713 + yyRuleName[yyruleno]);
12715 +#endif /* NDEBUG */
12717 + switch( yyruleno ){
12718 + /* Beginning here are the reduction cases. A typical example
12721 + ** #line <lineno> <grammarfile>
12722 + ** { ... } // User supplied code
12723 + ** #line <lineno> <thisfile>
12727 +#line 28 "./http_resp_parser.y"
12729 + http_resp *resp = ctx->resp;
12732 + resp->protocol = HTTP_VERSION_UNSET;
12734 + buffer_copy_string(resp->reason, ""); /* no reason */
12735 + array_free(resp->headers);
12736 + resp->headers = yymsp[-1].minor.yy12;
12738 + if (NULL == (ds = (data_string *)array_get_element(yymsp[-1].minor.yy12, "Status"))) {
12739 + resp->status = 0;
12742 + resp->status = strtol(ds->value->ptr, &err, 10);
12744 + if (*err != '\0' && *err != ' ') {
12745 + buffer_copy_string(ctx->errmsg, "expected a number: ");
12746 + buffer_append_string_buffer(ctx->errmsg, ds->value);
12747 + buffer_append_string(ctx->errmsg, err);
12753 + yymsp[-1].minor.yy12 = NULL;
12755 +#line 582 "http_resp_parser.c"
12756 + yy_destructor(1,&yymsp[0].minor);
12759 +#line 56 "./http_resp_parser.y"
12761 + http_resp *resp = ctx->resp;
12763 + resp->status = yymsp[-4].minor.yy20;
12764 + resp->protocol = yymsp[-5].minor.yy20;
12765 + buffer_copy_string_buffer(resp->reason, yymsp[-3].minor.yy0);
12766 + buffer_free(yymsp[-3].minor.yy0);
12768 + array_free(resp->headers);
12770 + resp->headers = yymsp[-1].minor.yy12;
12772 +#line 599 "http_resp_parser.c"
12773 + yy_destructor(1,&yymsp[-2].minor);
12774 + yy_destructor(1,&yymsp[0].minor);
12777 +#line 69 "./http_resp_parser.y"
12779 + if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.0"))) {
12780 + yygotominor.yy20 = HTTP_VERSION_1_0;
12781 + } else if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.1"))) {
12782 + yygotominor.yy20 = HTTP_VERSION_1_1;
12784 + buffer_copy_string(ctx->errmsg, "unknown protocol: ");
12785 + buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
12789 + buffer_free(yymsp[0].minor.yy0);
12791 +#line 618 "http_resp_parser.c"
12794 +#line 83 "./http_resp_parser.y"
12797 + yygotominor.yy20 = strtol(yymsp[0].minor.yy0->ptr, &err, 10);
12799 + if (*err != '\0') {
12800 + buffer_copy_string(ctx->errmsg, "expected a number, got: ");
12801 + buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
12805 + buffer_free(yymsp[0].minor.yy0);
12807 +#line 634 "http_resp_parser.c"
12810 +#line 96 "./http_resp_parser.y"
12812 + yygotominor.yy0 = yymsp[0].minor.yy0;
12814 +#line 641 "http_resp_parser.c"
12817 +#line 100 "./http_resp_parser.y"
12819 + yygotominor.yy0 = yymsp[-1].minor.yy0;
12821 + buffer_append_string(yygotominor.yy0, " ");
12822 + buffer_append_string_buffer(yygotominor.yy0, yymsp[0].minor.yy0);
12824 + buffer_free(yymsp[0].minor.yy0);
12826 +#line 653 "http_resp_parser.c"
12829 +#line 109 "./http_resp_parser.y"
12831 + yygotominor.yy12 = yymsp[-1].minor.yy12;
12833 + array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
12835 +#line 662 "http_resp_parser.c"
12838 +#line 115 "./http_resp_parser.y"
12840 + yygotominor.yy12 = array_init();
12842 + array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
12844 +#line 671 "http_resp_parser.c"
12847 +#line 120 "./http_resp_parser.y"
12849 + yygotominor.yy9 = data_string_init();
12851 + buffer_copy_string_buffer(yygotominor.yy9->key, yymsp[-3].minor.yy0);
12852 + buffer_copy_string_buffer(yygotominor.yy9->value, yymsp[-1].minor.yy0);
12853 + buffer_free(yymsp[-3].minor.yy0);
12854 + buffer_free(yymsp[-1].minor.yy0);
12856 +#line 683 "http_resp_parser.c"
12857 + yy_destructor(3,&yymsp[-2].minor);
12858 + yy_destructor(1,&yymsp[0].minor);
12861 + yygoto = yyRuleInfo[yyruleno].lhs;
12862 + yysize = yyRuleInfo[yyruleno].nrhs;
12863 + yypParser->yyidx -= yysize;
12864 + yyact = yy_find_reduce_action(yypParser,yygoto);
12865 + if( yyact < YYNSTATE ){
12866 + yy_shift(yypParser,yyact,yygoto,&yygotominor);
12867 + }else if( yyact == YYNSTATE + YYNRULE + 1 ){
12868 + yy_accept(yypParser);
12873 +** The following code executes when the parse fails
12875 +static void yy_parse_failed(
12876 + yyParser *yypParser /* The parser */
12878 + http_resp_parserARG_FETCH;
12880 + if( yyTraceFILE ){
12881 + fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
12884 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12885 + /* Here code is inserted which will be executed whenever the
12886 + ** parser fails */
12887 +#line 15 "./http_resp_parser.y"
12891 +#line 718 "http_resp_parser.c"
12892 + http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12896 +** The following code executes when a syntax error first occurs.
12898 +static void yy_syntax_error(
12899 + yyParser *yypParser, /* The parser */
12900 + int yymajor, /* The major type of the error token */
12901 + YYMINORTYPE yyminor /* The minor type of the error token */
12903 + http_resp_parserARG_FETCH;
12904 +#define TOKEN (yyminor.yy0)
12905 + http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12909 +** The following is executed when the parser accepts
12911 +static void yy_accept(
12912 + yyParser *yypParser /* The parser */
12914 + http_resp_parserARG_FETCH;
12916 + if( yyTraceFILE ){
12917 + fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
12920 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12921 + /* Here code is inserted which will be executed whenever the
12922 + ** parser accepts */
12923 + http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12926 +/* The main parser program.
12927 +** The first argument is a pointer to a structure obtained from
12928 +** "http_resp_parserAlloc" which describes the current state of the parser.
12929 +** The second argument is the major token number. The third is
12930 +** the minor token. The fourth optional argument is whatever the
12931 +** user wants (and specified in the grammar) and is available for
12932 +** use by the action routines.
12936 +** <li> A pointer to the parser (an opaque structure.)
12937 +** <li> The major token number.
12938 +** <li> The minor token number.
12939 +** <li> An option argument of a grammar-specified type.
12945 +void http_resp_parser(
12946 + void *yyp, /* The parser */
12947 + int yymajor, /* The major token code number */
12948 + http_resp_parserTOKENTYPE yyminor /* The value for the token */
12949 + http_resp_parserARG_PDECL /* Optional %extra_argument parameter */
12951 + YYMINORTYPE yyminorunion;
12952 + int yyact; /* The parser action. */
12953 + int yyendofinput; /* True if we are at the end of input */
12954 + int yyerrorhit = 0; /* True if yymajor has invoked an error */
12955 + yyParser *yypParser; /* The parser */
12957 + /* (re)initialize the parser, if necessary */
12958 + yypParser = (yyParser*)yyp;
12959 + if( yypParser->yyidx<0 ){
12960 + if( yymajor==0 ) return;
12961 + yypParser->yyidx = 0;
12962 + yypParser->yyerrcnt = -1;
12963 + yypParser->yystack[0].stateno = 0;
12964 + yypParser->yystack[0].major = 0;
12966 + yyminorunion.yy0 = yyminor;
12967 + yyendofinput = (yymajor==0);
12968 + http_resp_parserARG_STORE;
12971 + if( yyTraceFILE ){
12972 + fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
12977 + yyact = yy_find_shift_action(yypParser,yymajor);
12978 + if( yyact<YYNSTATE ){
12979 + yy_shift(yypParser,yyact,yymajor,&yyminorunion);
12980 + yypParser->yyerrcnt--;
12981 + if( yyendofinput && yypParser->yyidx>=0 ){
12984 + yymajor = YYNOCODE;
12986 + }else if( yyact < YYNSTATE + YYNRULE ){
12987 + yy_reduce(yypParser,yyact-YYNSTATE);
12988 + }else if( yyact == YY_ERROR_ACTION ){
12991 + if( yyTraceFILE ){
12992 + fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
12995 +#ifdef YYERRORSYMBOL
12996 + /* A syntax error has occurred.
12997 + ** The response to an error depends upon whether or not the
12998 + ** grammar defines an error token "ERROR".
13000 + ** This is what we do if the grammar does define ERROR:
13002 + ** * Call the %syntax_error function.
13004 + ** * Begin popping the stack until we enter a state where
13005 + ** it is legal to shift the error symbol, then shift
13006 + ** the error symbol.
13008 + ** * Set the error count to three.
13010 + ** * Begin accepting and shifting new tokens. No new error
13011 + ** processing will occur until three tokens have been
13012 + ** shifted successfully.
13015 + if( yypParser->yyerrcnt<0 ){
13016 + yy_syntax_error(yypParser,yymajor,yyminorunion);
13018 + yymx = yypParser->yystack[yypParser->yyidx].major;
13019 + if( yymx==YYERRORSYMBOL || yyerrorhit ){
13021 + if( yyTraceFILE ){
13022 + fprintf(yyTraceFILE,"%sDiscard input token %s\n",
13023 + yyTracePrompt,yyTokenName[yymajor]);
13026 + yy_destructor(yymajor,&yyminorunion);
13027 + yymajor = YYNOCODE;
13030 + yypParser->yyidx >= 0 &&
13031 + yymx != YYERRORSYMBOL &&
13032 + (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
13034 + yy_pop_parser_stack(yypParser);
13036 + if( yypParser->yyidx < 0 || yymajor==0 ){
13037 + yy_destructor(yymajor,&yyminorunion);
13038 + yy_parse_failed(yypParser);
13039 + yymajor = YYNOCODE;
13040 + }else if( yymx!=YYERRORSYMBOL ){
13042 + u2.YYERRSYMDT = 0;
13043 + yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
13046 + yypParser->yyerrcnt = 3;
13048 +#else /* YYERRORSYMBOL is not defined */
13049 + /* This is what we do if the grammar does not define ERROR:
13051 + ** * Report an error message, and throw away the input token.
13053 + ** * If the input token is $, then fail the parse.
13055 + ** As before, subsequent error messages are suppressed until
13056 + ** three input tokens have been successfully shifted.
13058 + if( yypParser->yyerrcnt<=0 ){
13059 + yy_syntax_error(yypParser,yymajor,yyminorunion);
13061 + yypParser->yyerrcnt = 3;
13062 + yy_destructor(yymajor,&yyminorunion);
13063 + if( yyendofinput ){
13064 + yy_parse_failed(yypParser);
13066 + yymajor = YYNOCODE;
13069 + yy_accept(yypParser);
13070 + yymajor = YYNOCODE;
13072 + }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
13075 --- ../lighttpd-1.4.11/src/http_resp_parser.h 1970-01-01 03:00:00.000000000 +0300
13076 +++ lighttpd-1.4.12/src/http_resp_parser.h 2006-07-18 13:03:52.000000000 +0300
13079 +#define TK_STRING 2
13080 +#define TK_COLON 3
13081 --- ../lighttpd-1.4.11/src/http_resp_parser.y 1970-01-01 03:00:00.000000000 +0300
13082 +++ lighttpd-1.4.12/src/http_resp_parser.y 2006-07-18 13:03:40.000000000 +0300
13085 +%token_type {buffer *}
13086 +%extra_argument {http_resp_ctx_t *ctx}
13087 +%name http_resp_parser
13090 +#include <assert.h>
13091 +#include <string.h>
13092 +#include "http_resp.h"
13093 +#include "keyvalue.h"
13094 +#include "array.h"
13102 +%type protocol { int }
13103 +%type response_hdr { http_resp * }
13104 +%type number { int }
13105 +%type headers { array * }
13106 +%type header { data_string * }
13107 +%destructor reason { buffer_free($$); }
13108 +%token_destructor { buffer_free($$); }
13110 +/* just headers + Status: ... */
13111 +response_hdr ::= headers(HDR) CRLF . {
13112 + http_resp *resp = ctx->resp;
13115 + resp->protocol = HTTP_VERSION_UNSET;
13117 + buffer_copy_string(resp->reason, ""); /* no reason */
13118 + array_free(resp->headers);
13119 + resp->headers = HDR;
13121 + if (NULL == (ds = (data_string *)array_get_element(HDR, "Status"))) {
13122 + resp->status = 0;
13125 + resp->status = strtol(ds->value->ptr, &err, 10);
13127 + if (*err != '\0' && *err != ' ') {
13128 + buffer_copy_string(ctx->errmsg, "expected a number: ");
13129 + buffer_append_string_buffer(ctx->errmsg, ds->value);
13130 + buffer_append_string(ctx->errmsg, err);
13138 +/* HTTP/1.0 <status> ... */
13139 +response_hdr ::= protocol(B) number(C) reason(D) CRLF headers(HDR) CRLF . {
13140 + http_resp *resp = ctx->resp;
13142 + resp->status = C;
13143 + resp->protocol = B;
13144 + buffer_copy_string_buffer(resp->reason, D);
13147 + array_free(resp->headers);
13149 + resp->headers = HDR;
13152 +protocol(A) ::= STRING(B). {
13153 + if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.0"))) {
13154 + A = HTTP_VERSION_1_0;
13155 + } else if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.1"))) {
13156 + A = HTTP_VERSION_1_1;
13158 + buffer_copy_string(ctx->errmsg, "unknown protocol: ");
13159 + buffer_append_string_buffer(ctx->errmsg, B);
13166 +number(A) ::= STRING(B). {
13168 + A = strtol(B->ptr, &err, 10);
13170 + if (*err != '\0') {
13171 + buffer_copy_string(ctx->errmsg, "expected a number, got: ");
13172 + buffer_append_string_buffer(ctx->errmsg, B);
13179 +reason(A) ::= STRING(B). {
13183 +reason(A) ::= reason(C) STRING(B). {
13186 + buffer_append_string(A, " ");
13187 + buffer_append_string_buffer(A, B);
13192 +headers(HDRS) ::= headers(SRC) header(HDR). {
13195 + array_insert_unique(HDRS, (data_unset *)HDR);
13198 +headers(HDRS) ::= header(HDR). {
13199 + HDRS = array_init();
13201 + array_insert_unique(HDRS, (data_unset *)HDR);
13203 +header(HDR) ::= STRING(A) COLON STRING(B) CRLF. {
13204 + HDR = data_string_init();
13206 + buffer_copy_string_buffer(HDR->key, A);
13207 + buffer_copy_string_buffer(HDR->value, B);
13211 --- ../lighttpd-1.4.11/src/inet_ntop_cache.c 2005-08-11 01:26:38.000000000 +0300
13212 +++ lighttpd-1.4.12/src/inet_ntop_cache.c 2006-07-16 00:26:04.000000000 +0300
13214 #include "sys-socket.h"
13216 const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) {
13220 for (i = 0; i < INET_NTOP_CACHE_MAX; i++) {
13221 if (srv->inet_ntop_cache[i].ts != 0) {
13222 @@ -20,31 +20,31 @@
13223 srv->inet_ntop_cache[i].addr.ipv4.s_addr == addr->ipv4.sin_addr.s_addr) {
13224 /* IPv4 found in cache */
13233 if (i == INET_NTOP_CACHE_MAX) {
13234 /* not found in cache */
13238 - inet_ntop(addr->plain.sa_family,
13239 - addr->plain.sa_family == AF_INET6 ?
13240 + inet_ntop(addr->plain.sa_family,
13241 + addr->plain.sa_family == AF_INET6 ?
13242 (const void *) &(addr->ipv6.sin6_addr) :
13243 (const void *) &(addr->ipv4.sin_addr),
13244 srv->inet_ntop_cache[i].b2, INET6_ADDRSTRLEN);
13247 srv->inet_ntop_cache[i].ts = srv->cur_ts;
13248 srv->inet_ntop_cache[i].family = addr->plain.sa_family;
13251 if (srv->inet_ntop_cache[i].family == AF_INET) {
13252 srv->inet_ntop_cache[i].addr.ipv4.s_addr = addr->ipv4.sin_addr.s_addr;
13253 } else if (srv->inet_ntop_cache[i].family == AF_INET6) {
13254 memcpy(srv->inet_ntop_cache[i].addr.ipv6.s6_addr, addr->ipv6.sin6_addr.s6_addr, 16);
13259 return srv->inet_ntop_cache[i].b2;
13262 --- ../lighttpd-1.4.11/src/iosocket.c 1970-01-01 03:00:00.000000000 +0300
13263 +++ lighttpd-1.4.12/src/iosocket.c 2006-07-18 13:03:40.000000000 +0300
13265 +#include <stdlib.h>
13267 +#include "iosocket.h"
13268 +#include "sys-socket.h"
13269 +#include "sys-files.h"
13270 +#include "array-static.h"
13272 +iosocket *iosocket_init(void) {
13273 + STRUCT_INIT(iosocket, sock);
13275 + sock->fde_ndx = -1;
13278 + sock->type = IOSOCKET_TYPE_SOCKET;
13283 +void iosocket_free(iosocket *sock) {
13284 + if (!sock) return;
13286 + if (sock->fd != -1) {
13287 + switch (sock->type) {
13288 + case IOSOCKET_TYPE_SOCKET:
13289 + closesocket(sock->fd);
13291 + case IOSOCKET_TYPE_PIPE:
13301 --- ../lighttpd-1.4.11/src/iosocket.h 1970-01-01 03:00:00.000000000 +0300
13302 +++ lighttpd-1.4.12/src/iosocket.h 2006-07-18 13:03:40.000000000 +0300
13304 +#ifndef _IOSOCKET_H_
13305 +#define _IOSOCKET_H_
13307 +#if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
13308 +# define USE_OPENSSL
13309 +# include <openssl/ssl.h>
13313 + IOSOCKET_TYPE_UNSET,
13314 + IOSOCKET_TYPE_SOCKET,
13315 + IOSOCKET_TYPE_PIPE
13319 + * a non-blocking fd
13325 +#ifdef USE_OPENSSL
13329 + iosocket_t type; /**< sendfile on solaris doesn't work on pipes */
13332 +iosocket *iosocket_init(void);
13333 +void iosocket_free(iosocket *sock);
13336 --- ../lighttpd-1.4.11/src/joblist.c 2005-08-11 01:26:41.000000000 +0300
13337 +++ lighttpd-1.4.12/src/joblist.c 2006-07-16 00:26:03.000000000 +0300
13340 int joblist_append(server *srv, connection *con) {
13341 if (con->in_joblist) return 0;
13344 if (srv->joblist->size == 0) {
13345 srv->joblist->size = 16;
13346 srv->joblist->ptr = malloc(sizeof(*srv->joblist->ptr) * srv->joblist->size);
13347 @@ -15,15 +15,15 @@
13348 srv->joblist->size += 16;
13349 srv->joblist->ptr = realloc(srv->joblist->ptr, sizeof(*srv->joblist->ptr) * srv->joblist->size);
13353 srv->joblist->ptr[srv->joblist->used++] = con;
13359 void joblist_free(server *srv, connections *joblist) {
13363 free(joblist->ptr);
13366 @@ -31,14 +31,14 @@
13367 connection *fdwaitqueue_unshift(server *srv, connections *fdwaitqueue) {
13374 if (fdwaitqueue->used == 0) return NULL;
13377 con = fdwaitqueue->ptr[0];
13380 memmove(fdwaitqueue->ptr, &(fdwaitqueue->ptr[1]), --fdwaitqueue->used * sizeof(*(fdwaitqueue->ptr)));
13387 srv->fdwaitqueue->size += 16;
13388 srv->fdwaitqueue->ptr = realloc(srv->fdwaitqueue->ptr, sizeof(*(srv->fdwaitqueue->ptr)) * srv->fdwaitqueue->size);
13392 srv->fdwaitqueue->ptr[srv->fdwaitqueue->used++] = con;
13398 --- ../lighttpd-1.4.11/src/keyvalue.c 2006-03-02 16:08:06.000000000 +0200
13399 +++ lighttpd-1.4.12/src/keyvalue.c 2006-07-16 00:26:03.000000000 +0300
13401 { 504, "Gateway Timeout" },
13402 { 505, "HTTP Version Not Supported" },
13403 { 507, "Insufficient Storage" }, /* WebDAV */
13405 + { 509, "Bandwidth Limit exceeded" },
13410 @@ -102,12 +103,12 @@
13411 { 501, "501.html" },
13412 { 503, "503.html" },
13413 { 505, "505.html" },
13420 -const char *keyvalue_get_value(keyvalue *kv, int k) {
13421 +const char *keyvalue_get_value(keyvalue *kv, int k) {
13423 for (i = 0; kv[i].value; i++) {
13424 if (kv[i].key == k) return kv[i].value;
13425 @@ -115,7 +116,7 @@
13429 -int keyvalue_get_key(keyvalue *kv, const char *s) {
13430 +int keyvalue_get_key(keyvalue *kv, const char *s) {
13432 for (i = 0; kv[i].value; i++) {
13433 if (0 == strcmp(kv[i].value, s)) return kv[i].key;
13434 @@ -125,9 +126,9 @@
13436 keyvalue_buffer *keyvalue_buffer_init(void) {
13437 keyvalue_buffer *kvb;
13440 kvb = calloc(1, sizeof(*kvb));
13446 @@ -135,49 +136,49 @@
13448 if (kvb->size == 0) {
13452 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13455 for(i = 0; i < kvb->size; i++) {
13456 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13458 } else if (kvb->used == kvb->size) {
13462 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13465 for(i = kvb->used; i < kvb->size; i++) {
13466 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13471 kvb->kv[kvb->used]->key = key;
13472 kvb->kv[kvb->used]->value = strdup(value);
13481 void keyvalue_buffer_free(keyvalue_buffer *kvb) {
13485 for (i = 0; i < kvb->size; i++) {
13486 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
13491 if (kvb->kv) free(kvb->kv);
13498 s_keyvalue_buffer *s_keyvalue_buffer_init(void) {
13499 s_keyvalue_buffer *kvb;
13502 kvb = calloc(1, sizeof(*kvb));
13508 @@ -186,50 +187,50 @@
13509 if (kvb->size == 0) {
13514 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13517 for(i = 0; i < kvb->size; i++) {
13518 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13520 } else if (kvb->used == kvb->size) {
13524 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13527 for(i = kvb->used; i < kvb->size; i++) {
13528 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13533 kvb->kv[kvb->used]->key = key ? strdup(key) : NULL;
13534 kvb->kv[kvb->used]->value = strdup(value);
13543 void s_keyvalue_buffer_free(s_keyvalue_buffer *kvb) {
13547 for (i = 0; i < kvb->size; i++) {
13548 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
13549 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
13554 if (kvb->kv) free(kvb->kv);
13561 httpauth_keyvalue_buffer *httpauth_keyvalue_buffer_init(void) {
13562 httpauth_keyvalue_buffer *kvb;
13565 kvb = calloc(1, sizeof(*kvb));
13571 @@ -237,42 +238,42 @@
13573 if (kvb->size == 0) {
13577 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13580 for(i = 0; i < kvb->size; i++) {
13581 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13583 } else if (kvb->used == kvb->size) {
13587 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13590 for(i = kvb->used; i < kvb->size; i++) {
13591 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13596 kvb->kv[kvb->used]->key = strdup(key);
13597 kvb->kv[kvb->used]->realm = strdup(realm);
13598 kvb->kv[kvb->used]->type = type;
13607 void httpauth_keyvalue_buffer_free(httpauth_keyvalue_buffer *kvb) {
13611 for (i = 0; i < kvb->size; i++) {
13612 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
13613 if (kvb->kv[i]->realm) free(kvb->kv[i]->realm);
13618 if (kvb->kv) free(kvb->kv);
13624 @@ -306,9 +307,9 @@
13626 pcre_keyvalue_buffer *pcre_keyvalue_buffer_init(void) {
13627 pcre_keyvalue_buffer *kvb;
13630 kvb = calloc(1, sizeof(*kvb));
13636 @@ -319,46 +320,46 @@
13642 if (!key) return -1;
13645 if (kvb->size == 0) {
13650 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13653 for(i = 0; i < kvb->size; i++) {
13654 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13656 } else if (kvb->used == kvb->size) {
13660 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13663 for(i = kvb->used; i < kvb->size; i++) {
13664 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13669 kv = kvb->kv[kvb->used];
13670 if (NULL == (kv->key = pcre_compile(key,
13671 0, &errptr, &erroff, NULL))) {
13674 fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr);
13678 - if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
13679 + if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
13685 kv->value = buffer_init_string(value);
13694 @@ -380,9 +381,9 @@
13695 if (kv->value) buffer_free(kv->value);
13700 if (kvb->kv) free(kvb->kv);
13706 --- ../lighttpd-1.4.11/src/keyvalue.h 2006-03-02 16:08:06.000000000 +0200
13707 +++ lighttpd-1.4.12/src/keyvalue.h 2006-07-16 00:26:04.000000000 +0300
13713 - HTTP_METHOD_UNSET = -1,
13715 - HTTP_METHOD_POST,
13716 - HTTP_METHOD_HEAD,
13717 - HTTP_METHOD_OPTIONS,
13719 + HTTP_METHOD_UNSET = -1,
13721 + HTTP_METHOD_POST,
13722 + HTTP_METHOD_HEAD,
13723 + HTTP_METHOD_OPTIONS,
13724 HTTP_METHOD_PROPFIND, /* WebDAV */
13725 - HTTP_METHOD_MKCOL,
13727 - HTTP_METHOD_DELETE,
13728 - HTTP_METHOD_COPY,
13729 - HTTP_METHOD_MOVE,
13730 - HTTP_METHOD_PROPPATCH,
13731 + HTTP_METHOD_MKCOL,
13733 + HTTP_METHOD_DELETE,
13734 + HTTP_METHOD_COPY,
13735 + HTTP_METHOD_MOVE,
13736 + HTTP_METHOD_PROPPATCH,
13737 HTTP_METHOD_REPORT, /* DeltaV */
13738 HTTP_METHOD_CHECKOUT,
13739 HTTP_METHOD_CHECKIN,
13740 @@ -39,13 +39,13 @@
13758 pcre_extra *key_extra;
13772 httpauth_type type;
13773 } httpauth_keyvalue;
13774 --- ../lighttpd-1.4.11/src/lemon.c 2005-09-01 00:21:34.000000000 +0300
13775 +++ lighttpd-1.4.12/src/lemon.c 2006-07-16 00:26:03.000000000 +0300
13776 @@ -579,7 +579,7 @@
13779 /* Find a precedence symbol of every rule in the grammar.
13782 ** Those rules which have a precedence symbol coded in the input
13783 ** grammar using the "[symbol]" construct will already have the
13784 ** rp->precsym field filled. Other rules take as their precedence
13785 @@ -869,7 +869,7 @@
13786 cfp->status = INCOMPLETE;
13793 for(i=0; i<lemp->nstate; i++){
13794 @@ -900,7 +900,7 @@
13798 - /* Add all of the reduce actions
13799 + /* Add all of the reduce actions
13800 ** A reduce action is added for each element of the followset of
13801 ** a configuration which has its dot at the extreme right.
13803 @@ -1017,7 +1017,7 @@
13804 apx->type = RD_RESOLVED;
13809 apx->type==SH_RESOLVED ||
13810 apx->type==RD_RESOLVED ||
13811 apx->type==CONFLICT ||
13812 @@ -1350,7 +1350,7 @@
13813 OptInit(argv,options,stderr);
13815 printf("Lemon version 1.0\n");
13819 if( OptNArgs() < 1 ){
13820 fprintf(stderr,"Exactly one filename argument is required.\n");
13821 @@ -2031,7 +2031,7 @@
13825 - rp = (struct rule *)malloc( sizeof(struct rule) +
13826 + rp = (struct rule *)malloc( sizeof(struct rule) +
13827 sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs );
13829 ErrorMsg(psp->filename,psp->tokenlineno,
13830 @@ -2546,7 +2546,7 @@
13834 -/* Duplicate the input file without comments and without actions
13835 +/* Duplicate the input file without comments and without actions
13838 struct lemon *lemp;
13839 @@ -2822,7 +2822,7 @@
13840 PRIVATE FILE *tplt_open(lemp)
13841 struct lemon *lemp;
13848 @@ -2930,7 +2930,7 @@
13854 ** Generate code which executes when the rule "rp" is reduced. Write
13855 ** the code to "out". Make sure lineno stays up-to-date.
13857 @@ -3384,7 +3384,7 @@
13859 /* Output the yy_shift_ofst[] table */
13860 fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++;
13861 - fprintf(out, "static %s yy_shift_ofst[] = {\n",
13862 + fprintf(out, "static %s yy_shift_ofst[] = {\n",
13863 minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++;
13865 for(i=j=0; i<n; i++){
13866 @@ -3405,7 +3405,7 @@
13868 /* Output the yy_reduce_ofst[] table */
13869 fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++;
13870 - fprintf(out, "static %s yy_reduce_ofst[] = {\n",
13871 + fprintf(out, "static %s yy_reduce_ofst[] = {\n",
13872 minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++;
13874 for(i=j=0; i<n; i++){
13875 @@ -3480,7 +3480,7 @@
13876 tplt_xfer(lemp->name,in,out,&lineno);
13878 /* Generate code which executes every time a symbol is popped from
13879 - ** the stack while processing errors or while destroying the parser.
13880 + ** the stack while processing errors or while destroying the parser.
13881 ** (In other words, generate the %destructor actions)
13883 if( lemp->tokendest ){
13884 @@ -3522,7 +3522,7 @@
13885 tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno);
13886 tplt_xfer(lemp->name,in,out,&lineno);
13888 - /* Generate the table of rule information
13889 + /* Generate the table of rule information
13891 ** Note: This code depends on the fact that rules are number
13892 ** sequentually beginning with 0.
13893 @@ -3589,7 +3589,7 @@
13894 for(i=1; i<lemp->nterminal; i++){
13895 fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
13902 @@ -3630,7 +3630,7 @@
13908 /* Do not make a default if the number of rules to default
13909 ** is not at least 2 */
13910 if( nbest<2 ) continue;
13911 @@ -3781,7 +3781,7 @@
13915 - x1a->tbl = (x1node*)malloc(
13916 + x1a->tbl = (x1node*)malloc(
13917 (sizeof(x1node) + sizeof(x1node*))*1024 );
13920 @@ -3943,7 +3943,7 @@
13924 - x2a->tbl = (x2node*)malloc(
13925 + x2a->tbl = (x2node*)malloc(
13926 (sizeof(x2node) + sizeof(x2node*))*128 );
13929 @@ -4149,7 +4149,7 @@
13933 - x3a->tbl = (x3node*)malloc(
13934 + x3a->tbl = (x3node*)malloc(
13935 (sizeof(x3node) + sizeof(x3node*))*128 );
13938 @@ -4295,7 +4295,7 @@
13942 - x4a->tbl = (x4node*)malloc(
13943 + x4a->tbl = (x4node*)malloc(
13944 (sizeof(x4node) + sizeof(x4node*))*64 );
13947 --- ../lighttpd-1.4.11/src/lempar.c 2005-08-11 01:26:40.000000000 +0300
13948 +++ lighttpd-1.4.12/src/lempar.c 2006-07-16 00:26:03.000000000 +0300
13950 /* Next is all token values, in a form suitable for use by makeheaders.
13951 ** This section will be null unless lemon is run with the -m switch.
13955 ** These constants (all generated automatically by the parser generator)
13956 ** specify the various kinds of tokens (terminals) that the parser
13960 ** Each symbol here is a terminal symbol in the grammar.
13963 ** and nonterminals. "int" is used otherwise.
13964 ** YYNOCODE is a number of type YYCODETYPE which corresponds
13965 ** to no legal terminal or nonterminal number. This
13966 -** number is used to fill in empty slots of the hash
13967 +** number is used to fill in empty slots of the hash
13969 ** YYFALLBACK If defined, this indicates that one or more tokens
13970 ** have fall-back values which should be used if the
13972 ** and nonterminal numbers. "unsigned char" is
13973 ** used if there are fewer than 250 rules and
13974 ** states combined. "int" is used otherwise.
13975 -** ParseTOKENTYPE is the data type used for minor tokens given
13976 +** ParseTOKENTYPE is the data type used for minor tokens given
13977 ** directly to the parser from the tokenizer.
13978 ** YYMINORTYPE is the data type used for all minor tokens.
13979 ** This is typically a union of many types, one of
13981 /* Next are that tables used to determine what action to take based on the
13982 ** current state and lookahead token. These tables are used to implement
13983 ** functions that take a state number and lookahead value and return an
13984 -** action integer.
13985 +** action integer.
13987 ** Suppose the action integer is N. Then the action is determined as
13990 ** If the index value yy_shift_ofst[S]+X is out of range or if the value
13991 ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
13992 ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
13993 -** and that yy_default[S] should be used instead.
13994 +** and that yy_default[S] should be used instead.
13996 ** The formula above is for computing the action when the lookahead is
13997 ** a terminal symbol. If the lookahead is a non-terminal (as occurs after
13998 @@ -111,7 +111,7 @@
14000 /* The next table maps tokens into fallback tokens. If a construct
14001 ** like the following:
14004 ** %fallback ID X Y Z.
14006 ** appears in the grammer, then ID becomes a fallback token for X, Y,
14007 @@ -163,10 +163,10 @@
14008 #endif /* NDEBUG */
14013 ** Turn parser tracing on by giving a stream to which to write the trace
14014 ** and a prompt to preface each trace message. Tracing is turned off
14015 -** by making either argument NULL
14016 +** by making either argument NULL
14020 @@ -191,7 +191,7 @@
14022 /* For tracing shifts, the names of all terminals and nonterminals
14023 ** are required. The following table supplies these names */
14024 -static const char *yyTokenName[] = {
14025 +static const char *yyTokenName[] = {
14028 #endif /* NDEBUG */
14029 @@ -220,7 +220,7 @@
14035 ** This function allocates a new parser.
14036 ** The only argument is a pointer to a function which works like
14038 @@ -251,7 +251,7 @@
14039 /* Here is inserted the actions which take place when a
14040 ** terminal or non-terminal is destroyed. This can happen
14041 ** when the symbol is popped from the stack during a
14042 - ** reduce or during error processing or when a parser is
14043 + ** reduce or during error processing or when a parser is
14044 ** being destroyed before it is finished parsing.
14046 ** Note: during a reduce, the only symbols destroyed are those
14047 @@ -289,7 +289,7 @@
14053 ** Deallocate and destroy a parser. Destructors are all called for
14054 ** all stack elements before shutting the parser down.
14056 @@ -325,7 +325,7 @@
14059 int stateno = pParser->yystack[pParser->yyidx].stateno;
14062 /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
14063 i = yy_shift_ofst[stateno];
14064 if( i==YY_SHIFT_USE_DFLT ){
14065 @@ -369,7 +369,7 @@
14068 int stateno = pParser->yystack[pParser->yyidx].stateno;
14071 i = yy_reduce_ofst[stateno];
14072 if( i==YY_REDUCE_USE_DFLT ){
14073 return yy_default[stateno];
14074 @@ -455,7 +455,7 @@
14076 yymsp = &yypParser->yystack[yypParser->yyidx];
14078 - if( yyTraceFILE && yyruleno>=0
14079 + if( yyTraceFILE && yyruleno>=0
14080 && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
14081 fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
14082 yyRuleName[yyruleno]);
14083 @@ -608,7 +608,7 @@
14084 #ifdef YYERRORSYMBOL
14085 /* A syntax error has occurred.
14086 ** The response to an error depends upon whether or not the
14087 - ** grammar defines an error token "ERROR".
14088 + ** grammar defines an error token "ERROR".
14090 ** This is what we do if the grammar does define ERROR:
14092 --- ../lighttpd-1.4.11/src/log.c 2005-11-07 15:01:35.000000000 +0200
14093 +++ lighttpd-1.4.12/src/log.c 2006-07-18 13:03:40.000000000 +0300
14098 -#include <unistd.h>
14099 #include <string.h>
14100 #include <stdlib.h>
14103 #include "config.h"
14107 +#undef HAVE_SYSLOG_H
14110 #ifdef HAVE_SYSLOG_H
14111 #include <syslog.h>
14117 +#include "sys-files.h"
14119 #ifdef HAVE_VALGRIND_VALGRIND_H
14120 #include <valgrind/valgrind.h>
14122 @@ -31,55 +36,114 @@
14123 # define O_LARGEFILE 0
14128 * open the errorlog
14131 * we have 3 possibilities:
14132 * - stderr (default)
14138 * if the open failed, report to the user and die
14143 -int log_error_open(server *srv) {
14147 + unsigned short use_syslog;
14149 + /* the errorlog */
14151 - int close_stderr = 1;
14152 + enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } mode;
14155 + time_t cached_ts;
14156 + buffer *cached_ts_str;
14159 +errorlog *myconfig = NULL;
14161 +void log_init(void) {
14165 + err = calloc(1, sizeof(*err));
14168 + err->mode = ERRORLOG_STDERR;
14169 + err->buf = buffer_init();
14170 + err->cached_ts_str = buffer_init();
14175 +void log_free(void) {
14176 + errorlog *err = myconfig;
14178 + if (!err) return;
14180 + TRACE("%s", "server stopped");
14182 + switch(err->mode) {
14183 + case ERRORLOG_FILE:
14186 + case ERRORLOG_SYSLOG:
14187 +#ifdef HAVE_SYSLOG_H
14191 + case ERRORLOG_STDERR:
14195 + buffer_free(err->buf);
14196 + buffer_free(err->cached_ts_str);
14197 + if (err->file) buffer_free(err->file);
14204 +int log_error_open(buffer *file, int use_syslog) {
14206 + int close_stderr = 1;
14208 + errorlog *err = myconfig;
14210 #ifdef HAVE_SYSLOG_H
14211 /* perhaps someone wants to use syslog() */
14212 openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON);
14214 - srv->errorlog_mode = ERRORLOG_STDERR;
14216 - if (srv->srvconf.errorlog_use_syslog) {
14217 - srv->errorlog_mode = ERRORLOG_SYSLOG;
14218 - } else if (!buffer_is_empty(srv->srvconf.errorlog_file)) {
14219 - const char *logfile = srv->srvconf.errorlog_file->ptr;
14221 - if (-1 == (srv->errorlog_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14222 - log_error_write(srv, __FILE__, __LINE__, "SSSS",
14223 - "opening errorlog '", logfile,
14224 + err->mode = ERRORLOG_STDERR;
14226 + if (use_syslog) {
14227 + err->mode = ERRORLOG_SYSLOG;
14228 + } else if (!buffer_is_empty(file)) {
14229 + if (-1 == (err->fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14230 + log_error_write(NULL, __FILE__, __LINE__, "SBSS",
14231 + "opening errorlog '", file,
14232 "' failed: ", strerror(errno));
14238 /* close fd on exec (cgi) */
14239 - fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC);
14240 + fcntl(err->fd, F_SETFD, FD_CLOEXEC);
14242 - srv->errorlog_mode = ERRORLOG_FILE;
14243 + err->mode = ERRORLOG_FILE;
14246 - log_error_write(srv, __FILE__, __LINE__, "s", "server started");
14249 + TRACE("%s", "server started");
14251 #ifdef HAVE_VALGRIND_VALGRIND_H
14252 /* don't close stderr for debugging purposes if run in valgrind */
14253 if (RUNNING_ON_VALGRIND) close_stderr = 0;
14255 - if (srv->errorlog_mode == ERRORLOG_STDERR) close_stderr = 0;
14257 + if (err->mode == ERRORLOG_STDERR) close_stderr = 0;
14259 /* move stderr to /dev/null */
14260 if (close_stderr &&
14261 -1 != (fd = open("/dev/null", O_WRONLY))) {
14262 @@ -90,167 +154,202 @@
14268 * open the errorlog
14271 * if the open failed, report to the user and die
14272 * if no filename is given, use syslog instead
14277 -int log_error_cycle(server *srv) {
14278 +int log_error_cycle(void) {
14279 /* only cycle if we are not in syslog-mode */
14281 - if (srv->errorlog_mode == ERRORLOG_FILE) {
14282 - const char *logfile = srv->srvconf.errorlog_file->ptr;
14284 + errorlog *err = myconfig;
14286 + if (err->mode == ERRORLOG_FILE) {
14287 + buffer *file = err->file;
14288 /* already check of opening time */
14293 - if (-1 == (new_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14295 + if (-1 == (new_fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14296 /* write to old log */
14297 - log_error_write(srv, __FILE__, __LINE__, "SSSSS",
14298 - "cycling errorlog '", logfile,
14299 + log_error_write(NULL, __FILE__, __LINE__, "SBSSS",
14300 + "cycling errorlog '", file,
14301 "' failed: ", strerror(errno),
14302 ", falling back to syslog()");
14304 - close(srv->errorlog_fd);
14305 - srv->errorlog_fd = -1;
14306 -#ifdef HAVE_SYSLOG_H
14307 - srv->errorlog_mode = ERRORLOG_SYSLOG;
14311 +#ifdef HAVE_SYSLOG_H
14312 + err->mode = ERRORLOG_SYSLOG;
14315 /* ok, new log is open, close the old one */
14316 - close(srv->errorlog_fd);
14317 - srv->errorlog_fd = new_fd;
14319 + err->fd = new_fd;
14323 - log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled");
14328 -int log_error_close(server *srv) {
14329 - log_error_write(srv, __FILE__, __LINE__, "s", "server stopped");
14331 - switch(srv->errorlog_mode) {
14332 - case ERRORLOG_FILE:
14333 - close(srv->errorlog_fd);
14335 - case ERRORLOG_SYSLOG:
14336 -#ifdef HAVE_SYSLOG_H
14340 - case ERRORLOG_STDERR:
14344 + TRACE("%s", "logfiles cycled");
14349 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
14350 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...) {
14353 - switch(srv->errorlog_mode) {
14356 + errorlog *err = myconfig;
14358 + switch(err->mode) {
14359 case ERRORLOG_FILE:
14360 case ERRORLOG_STDERR:
14361 /* cache the generated timestamp */
14362 - if (srv->cur_ts != srv->last_generated_debug_ts) {
14363 - buffer_prepare_copy(srv->ts_debug_str, 255);
14364 - strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
14365 - srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1;
14367 - srv->last_generated_debug_ts = srv->cur_ts;
14370 + if (t != err->cached_ts) {
14371 + buffer_prepare_copy(err->cached_ts_str, 255);
14372 + strftime(err->cached_ts_str->ptr, err->cached_ts_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(t)));
14373 + err->cached_ts_str->used = strlen(err->cached_ts_str->ptr) + 1;
14374 + err->cached_ts = t;
14377 - buffer_copy_string_buffer(srv->errorlog_buf, srv->ts_debug_str);
14378 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ": (");
14379 + buffer_copy_string_buffer(err->buf, err->cached_ts_str);
14380 + BUFFER_APPEND_STRING_CONST(err->buf, ": (");
14382 case ERRORLOG_SYSLOG:
14383 /* syslog is generating its own timestamps */
14384 - BUFFER_COPY_STRING_CONST(srv->errorlog_buf, "(");
14385 + BUFFER_COPY_STRING_CONST(err->buf, "(");
14389 - buffer_append_string(srv->errorlog_buf, filename);
14390 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ".");
14391 - buffer_append_long(srv->errorlog_buf, line);
14392 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ") ");
14396 + buffer_append_string(err->buf, filename);
14397 + BUFFER_APPEND_STRING_CONST(err->buf, ".");
14398 + buffer_append_long(err->buf, line);
14399 + BUFFER_APPEND_STRING_CONST(err->buf, ") ");
14401 for(va_start(ap, fmt); *fmt; fmt++) {
14409 case 's': /* string */
14410 s = va_arg(ap, char *);
14411 - buffer_append_string(srv->errorlog_buf, s);
14412 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14413 + buffer_append_string(err->buf, s);
14414 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
14416 case 'b': /* buffer */
14417 b = va_arg(ap, buffer *);
14418 - buffer_append_string_buffer(srv->errorlog_buf, b);
14419 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14420 + buffer_append_string_buffer(err->buf, b);
14421 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
14423 case 'd': /* int */
14424 d = va_arg(ap, int);
14425 - buffer_append_long(srv->errorlog_buf, d);
14426 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14427 + buffer_append_long(err->buf, d);
14428 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
14430 case 'o': /* off_t */
14431 o = va_arg(ap, off_t);
14432 - buffer_append_off_t(srv->errorlog_buf, o);
14433 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14434 + buffer_append_off_t(err->buf, o);
14435 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
14437 case 'x': /* int (hex) */
14438 d = va_arg(ap, int);
14439 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "0x");
14440 - buffer_append_long_hex(srv->errorlog_buf, d);
14441 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14442 + BUFFER_APPEND_STRING_CONST(err->buf, "0x");
14443 + buffer_append_long_hex(err->buf, d);
14444 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
14446 case 'S': /* string */
14447 s = va_arg(ap, char *);
14448 - buffer_append_string(srv->errorlog_buf, s);
14449 + buffer_append_string(err->buf, s);
14451 case 'B': /* buffer */
14452 b = va_arg(ap, buffer *);
14453 - buffer_append_string_buffer(srv->errorlog_buf, b);
14454 + buffer_append_string_buffer(err->buf, b);
14456 case 'D': /* int */
14457 d = va_arg(ap, int);
14458 - buffer_append_long(srv->errorlog_buf, d);
14459 + buffer_append_long(err->buf, d);
14468 - buffer_append_string_len(srv->errorlog_buf, fmt, 1);
14469 + buffer_append_string_len(err->buf, fmt, 1);
14475 - switch(srv->errorlog_mode) {
14477 + switch(err->mode) {
14478 case ERRORLOG_FILE:
14479 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
14480 - write(srv->errorlog_fd, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
14481 + BUFFER_APPEND_STRING_CONST(err->buf, "\n");
14482 + write(err->fd, err->buf->ptr, err->buf->used - 1);
14484 case ERRORLOG_STDERR:
14485 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
14486 - write(STDERR_FILENO, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
14487 + BUFFER_APPEND_STRING_CONST(err->buf, "\n");
14488 + write(STDERR_FILENO, err->buf->ptr, err->buf->used - 1);
14490 +#ifdef HAVE_SYSLOG_H
14491 + case ERRORLOG_SYSLOG:
14492 + syslog(LOG_ERR, "%s", err->buf->ptr);
14500 +static int log_trace_write(const char *fmt, va_list ap) {
14503 + errorlog *err = myconfig;
14505 + b = buffer_init();
14506 + buffer_prepare_copy(b, 1024);
14507 + l = vsnprintf(b->ptr, b->size - 1, fmt, ap);
14509 + b->used = (l > b->size - 1) ? b->size : l + 1;
14513 + switch(err->mode) {
14514 + case ERRORLOG_FILE:
14515 + buffer_append_string(b, "\r\n");
14516 + write(err->fd, b->ptr, b->used - 1);
14518 + case ERRORLOG_STDERR:
14519 + buffer_append_string(b, "\r\n");
14520 + write(STDERR_FILENO, b->ptr, b->used - 1);
14522 +#ifdef HAVE_SYSLOG_H
14523 case ERRORLOG_SYSLOG:
14524 - syslog(LOG_ERR, "%s", srv->errorlog_buf->ptr);
14525 + syslog(LOG_ERR, "%s", b->ptr);
14535 +int log_trace(const char *fmt, ...) {
14538 + va_start(ap, fmt);
14540 + log_trace_write(fmt, ap);
14548 --- ../lighttpd-1.4.11/src/log.h 2005-08-11 01:26:36.000000000 +0300
14549 +++ lighttpd-1.4.12/src/log.h 2006-07-18 13:03:40.000000000 +0300
14554 -#include "server.h"
14555 +#include "buffer.h"
14557 -#define WP() log_error_write(srv, __FILE__, __LINE__, "");
14558 +void log_init(void);
14559 +void log_free(void);
14561 -int log_error_open(server *srv);
14562 -int log_error_close(server *srv);
14563 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...);
14564 -int log_error_cycle(server *srv);
14566 +int log_error_open(buffer *file, int use_syslog);
14567 +int log_error_close();
14568 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...);
14569 +int log_error_cycle();
14571 +#define ERROR(fmt, ...) \
14572 + log_trace("%s.%d: (error) "fmt, __FILE__, __LINE__, __VA_ARGS__)
14574 +#define TRACE(fmt, ...) \
14575 + log_trace("%s.%d: (trace) "fmt, __FILE__, __LINE__, __VA_ARGS__)
14577 +#define SEGFAULT() do { ERROR("%s", "Ooh, Ooh, Ooh. Something is not good ... going down"); abort(); } while(0)
14578 +int log_trace(const char *fmt, ...);
14580 --- ../lighttpd-1.4.11/src/md5.h 2005-11-17 16:20:40.000000000 +0200
14581 +++ lighttpd-1.4.12/src/md5.h 2006-07-16 00:26:04.000000000 +0300
14583 # include <inttypes.h>
14587 +#define UINT4 unsigned __int32
14588 +#define UINT2 unsigned __int16
14589 +#define POINTER unsigned char *
14591 #define UINT4 uint32_t
14592 #define UINT2 uint16_t
14593 #define POINTER unsigned char *
14598 --- ../lighttpd-1.4.11/src/mod_access.c 2006-01-14 19:44:54.000000000 +0200
14599 +++ lighttpd-1.4.12/src/mod_access.c 2006-07-16 00:26:04.000000000 +0300
14600 @@ -8,126 +8,125 @@
14602 #include "plugin.h"
14604 +#include "sys-strings.h"
14607 array *access_deny;
14614 plugin_config **config_storage;
14616 - plugin_config conf;
14618 + plugin_config conf;
14621 INIT_FUNC(mod_access_init) {
14625 p = calloc(1, sizeof(*p));
14631 FREE_FUNC(mod_access_free) {
14632 plugin_data *p = p_d;
14637 if (!p) return HANDLER_GO_ON;
14640 if (p->config_storage) {
14642 for (i = 0; i < srv->config_context->used; i++) {
14643 plugin_config *s = p->config_storage[i];
14646 array_free(s->access_deny);
14651 free(p->config_storage);
14658 return HANDLER_GO_ON;
14661 SETDEFAULTS_FUNC(mod_access_set_defaults) {
14662 plugin_data *p = p_d;
14665 - config_values_t cv[] = {
14667 + config_values_t cv[] = {
14668 { "url.access-deny", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
14669 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
14673 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
14676 for (i = 0; i < srv->config_context->used; i++) {
14680 s = calloc(1, sizeof(plugin_config));
14681 s->access_deny = array_init();
14684 cv[0].destination = s->access_deny;
14687 p->config_storage[i] = s;
14690 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
14691 return HANDLER_ERROR;
14696 return HANDLER_GO_ON;
14699 -#define PATCH(x) \
14700 - p->conf.x = s->x;
14701 static int mod_access_patch_connection(server *srv, connection *con, plugin_data *p) {
14703 plugin_config *s = p->config_storage[0];
14705 - PATCH(access_deny);
14707 + PATCH_OPTION(access_deny);
14709 /* skip the first, the global context */
14710 for (i = 1; i < srv->config_context->used; i++) {
14711 data_config *dc = (data_config *)srv->config_context->data[i];
14712 s = p->config_storage[i];
14715 /* condition didn't match */
14716 if (!config_check_cond(srv, con, dc)) continue;
14720 for (j = 0; j < dc->value->used; j++) {
14721 data_unset *du = dc->value->data[j];
14724 if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.access-deny"))) {
14725 - PATCH(access_deny);
14726 + PATCH_OPTION(access_deny);
14736 URIHANDLER_FUNC(mod_access_uri_handler) {
14737 plugin_data *p = p_d;
14742 if (con->uri.path->used == 0) return HANDLER_GO_ON;
14745 mod_access_patch_connection(srv, con, p);
14748 s_len = con->uri.path->used - 1;
14751 for (k = 0; k < p->conf.access_deny->used; k++) {
14752 data_string *ds = (data_string *)p->conf.access_deny->data[k];
14753 int ct_len = ds->value->used - 1;
14756 if (ct_len > s_len) continue;
14759 if (ds->value->used == 0) continue;
14761 /* if we have a case-insensitive FS we have to lower-case the URI here too */
14762 @@ -135,18 +134,18 @@
14763 if (con->conf.force_lowercase_filenames) {
14764 if (0 == strncasecmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
14765 con->http_status = 403;
14768 return HANDLER_FINISHED;
14771 if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
14772 con->http_status = 403;
14775 return HANDLER_FINISHED;
14782 return HANDLER_GO_ON;
14784 @@ -155,13 +154,13 @@
14785 int mod_access_plugin_init(plugin *p) {
14786 p->version = LIGHTTPD_VERSION_ID;
14787 p->name = buffer_init_string("access");
14790 p->init = mod_access_init;
14791 p->set_defaults = mod_access_set_defaults;
14792 p->handle_uri_clean = mod_access_uri_handler;
14793 p->cleanup = mod_access_free;
14801 --- ../lighttpd-1.4.11/src/mod_accesslog.c 2006-01-31 14:01:43.000000000 +0200
14802 +++ lighttpd-1.4.12/src/mod_accesslog.c 2006-07-16 00:26:04.000000000 +0300
14805 #include <stdlib.h>
14806 #include <string.h>
14807 -#include <fcntl.h>
14808 -#include <unistd.h>
14809 +#include <fcntl.h> /* only the defines on windows */
14814 #include "inet_ntop_cache.h"
14816 #include "sys-socket.h"
14817 +#include "sys-files.h"
14819 #ifdef HAVE_SYSLOG_H
14820 # include <syslog.h>
14828 FORMAT_UNSUPPORTED,
14832 FORMAT_BYTES_OUT_NO_HEADER,
14836 FORMAT_REMOTE_ADDR,
14839 @@ -59,20 +59,20 @@
14840 FORMAT_CONNECTION_STATUS,
14845 FORMAT_RESPONSE_HEADER
14854 * "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
14859 -const format_mapping fmap[] =
14861 +const format_mapping fmap[] =
14863 { '%', FORMAT_PERCENT },
14864 { 'h', FORMAT_REMOTE_HOST },
14865 { 'l', FORMAT_REMOTE_IDENT },
14867 { 's', FORMAT_STATUS },
14868 { 'b', FORMAT_BYTES_OUT_NO_HEADER },
14869 { 'i', FORMAT_HEADER },
14872 { 'a', FORMAT_REMOTE_ADDR },
14873 { 'A', FORMAT_LOCAL_ADDR },
14874 { 'B', FORMAT_BYTES_OUT_NO_HEADER },
14875 @@ -103,23 +103,23 @@
14876 { 'X', FORMAT_CONNECTION_STATUS },
14877 { 'I', FORMAT_BYTES_IN },
14878 { 'O', FORMAT_BYTES_OUT },
14881 { 'o', FORMAT_RESPONSE_HEADER },
14884 { '\0', FORMAT_UNSET }
14889 enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type;
14897 format_field **ptr;
14903 @@ -128,39 +128,39 @@
14904 buffer *access_logfile;
14906 unsigned short use_syslog;
14912 time_t last_generated_accesslog_ts;
14913 time_t *last_generated_accesslog_ts_ptr;
14918 buffer *access_logbuffer;
14919 buffer *ts_accesslog_str;
14922 format_fields *parsed_format;
14929 plugin_config **config_storage;
14930 - plugin_config conf;
14931 + plugin_config conf;
14934 INIT_FUNC(mod_accesslog_init) {
14938 p = calloc(1, sizeof(*p));
14944 int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
14945 size_t i, j, k = 0, start = 0;
14948 for (i = 0; i < format->used - 1; i++) {
14951 switch(format->ptr[i]) {
14954 @@ -173,19 +173,19 @@
14955 fields->size += 16;
14956 fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
14960 fields->ptr[fields->used] = malloc(sizeof(format_fields));
14961 fields->ptr[fields->used]->type = FIELD_STRING;
14962 fields->ptr[fields->used]->string = buffer_init();
14965 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
14974 /* we need a new field */
14977 if (fields->size == 0) {
14980 @@ -194,43 +194,43 @@
14981 fields->size += 16;
14982 fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
14986 /* search for the terminating command */
14987 switch (format->ptr[i+1]) {
14993 for (j = 0; fmap[j].key != '\0'; j++) {
14994 if (fmap[j].key != format->ptr[i+2]) continue;
15000 fields->ptr[fields->used] = malloc(sizeof(format_fields));
15001 fields->ptr[fields->used]->type = FIELD_FORMAT;
15002 fields->ptr[fields->used]->field = fmap[j].type;
15003 fields->ptr[fields->used]->string = NULL;
15013 if (fmap[j].key == '\0') {
15014 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15024 /* go forward to } */
15027 for (k = i+2; k < format->used - 1; k++) {
15028 if (format->ptr[k] == '}') break;
15032 if (k == format->used - 1) {
15033 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15035 @@ -239,62 +239,62 @@
15036 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15041 for (j = 0; fmap[j].key != '\0'; j++) {
15042 if (fmap[j].key != format->ptr[k+1]) continue;
15048 fields->ptr[fields->used] = malloc(sizeof(format_fields));
15049 fields->ptr[fields->used]->type = FIELD_FORMAT;
15050 fields->ptr[fields->used]->field = fmap[j].type;
15051 fields->ptr[fields->used]->string = buffer_init();
15054 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + i + 2, k - (i + 2));
15064 if (fmap[j].key == '\0') {
15065 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15075 for (j = 0; fmap[j].key != '\0'; j++) {
15076 if (fmap[j].key != format->ptr[i+1]) continue;
15082 fields->ptr[fields->used] = malloc(sizeof(format_fields));
15083 fields->ptr[fields->used]->type = FIELD_FORMAT;
15084 fields->ptr[fields->used]->field = fmap[j].type;
15085 fields->ptr[fields->used]->string = NULL;
15095 if (fmap[j].key == '\0') {
15096 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15114 /* copy the string */
15115 if (fields->size == 0) {
15116 @@ -305,32 +305,32 @@
15117 fields->size += 16;
15118 fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
15122 fields->ptr[fields->used] = malloc(sizeof(format_fields));
15123 fields->ptr[fields->used]->type = FIELD_STRING;
15124 fields->ptr[fields->used]->string = buffer_init();
15127 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
15137 FREE_FUNC(mod_accesslog_free) {
15138 plugin_data *p = p_d;
15142 if (!p) return HANDLER_GO_ON;
15145 if (p->config_storage) {
15148 for (i = 0; i < srv->config_context->used; i++) {
15149 plugin_config *s = p->config_storage[i];
15154 if (s->access_logbuffer->used) {
15155 if (s->use_syslog) {
15156 # ifdef HAVE_SYSLOG_H
15157 @@ -342,14 +342,14 @@
15158 write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
15163 if (s->log_access_fd != -1) close(s->log_access_fd);
15166 buffer_free(s->ts_accesslog_str);
15167 buffer_free(s->access_logbuffer);
15168 buffer_free(s->format);
15169 buffer_free(s->access_logfile);
15172 if (s->parsed_format) {
15174 for (j = 0; j < s->parsed_format->used; j++) {
15175 @@ -359,36 +359,36 @@
15176 free(s->parsed_format->ptr);
15177 free(s->parsed_format);
15185 free(p->config_storage);
15192 return HANDLER_GO_ON;
15195 SETDEFAULTS_FUNC(log_access_open) {
15196 plugin_data *p = p_d;
15199 - config_values_t cv[] = {
15201 + config_values_t cv[] = {
15202 { "accesslog.filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
15203 { "accesslog.use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
15204 { "accesslog.format", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
15205 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
15209 if (!p) return HANDLER_ERROR;
15212 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
15215 for (i = 0; i < srv->config_context->used; i++) {
15219 s = calloc(1, sizeof(plugin_config));
15220 s->access_logfile = buffer_init();
15221 s->format = buffer_init();
15222 @@ -397,44 +397,44 @@
15223 s->log_access_fd = -1;
15224 s->last_generated_accesslog_ts = 0;
15225 s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts);
15230 cv[0].destination = s->access_logfile;
15231 cv[1].destination = &(s->use_syslog);
15232 cv[2].destination = s->format;
15235 p->config_storage[i] = s;
15238 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
15239 return HANDLER_ERROR;
15243 if (i == 0 && buffer_is_empty(s->format)) {
15244 /* set a default logfile string */
15247 buffer_copy_string(s->format, "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"");
15254 if (s->format->used) {
15255 s->parsed_format = calloc(1, sizeof(*(s->parsed_format)));
15258 if (-1 == accesslog_parse_format(srv, s->parsed_format, s->format)) {
15260 - log_error_write(srv, __FILE__, __LINE__, "sb",
15261 + log_error_write(srv, __FILE__, __LINE__, "sb",
15262 "parsing accesslog-definition failed:", s->format);
15264 return HANDLER_ERROR;
15269 for (j = 0; j < s->parsed_format->used; j++) {
15270 switch (s->parsed_format->ptr[j]->type) {
15272 - log_error_write(srv, __FILE__, __LINE__, "ssds",
15273 + log_error_write(srv, __FILE__, __LINE__, "ssds",
15274 "config:", "format", s->parsed_format->ptr[j]->field,
15275 - s->parsed_format->ptr[j]->string ?
15276 + s->parsed_format->ptr[j]->string ?
15277 s->parsed_format->ptr[j]->string->ptr : "" );
15280 @@ -446,52 +446,52 @@
15286 if (s->use_syslog) {
15287 /* ignore the next checks */
15292 if (buffer_is_empty(s->access_logfile)) continue;
15295 if (s->access_logfile->ptr[0] == '|') {
15297 /* create write pipe and spawn process */
15304 if (pipe(to_log_fds)) {
15305 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
15306 return HANDLER_ERROR;
15311 switch (pid = fork()) {
15317 close(STDIN_FILENO);
15318 dup2(to_log_fds[0], STDIN_FILENO);
15319 close(to_log_fds[0]);
15321 close(to_log_fds[1]);
15324 /* we don't need the client socket */
15325 for (i = 3; i < 256; i++) {
15329 - /* exec the log-process (skip the | )
15332 + /* exec the log-process (skip the | )
15337 execl("/bin/sh", "sh", "-c", s->access_logfile->ptr + 1, NULL);
15339 - log_error_write(srv, __FILE__, __LINE__, "sss",
15340 - "spawning log-process failed: ", strerror(errno),
15341 + log_error_write(srv, __FILE__, __LINE__, "sss",
15342 + "spawning log-process failed: ", strerror(errno),
15343 s->access_logfile->ptr + 1);
15349 @@ -500,27 +500,28 @@
15352 close(to_log_fds[0]);
15355 s->log_access_fd = to_log_fds[1];
15363 - } else if (-1 == (s->log_access_fd =
15364 + } else if (-1 == (s->log_access_fd =
15365 open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
15367 - log_error_write(srv, __FILE__, __LINE__, "ssb",
15368 - "opening access-log failed:",
15370 + log_error_write(srv, __FILE__, __LINE__, "ssb",
15371 + "opening access-log failed:",
15372 strerror(errno), s->access_logfile);
15375 return HANDLER_ERROR;
15378 fcntl(s->log_access_fd, F_SETFD, FD_CLOEXEC);
15384 return HANDLER_GO_ON;
15387 @@ -529,7 +530,7 @@
15390 if (!p->config_storage) return HANDLER_GO_ON;
15393 for (i = 0; i < srv->config_context->used; i++) {
15394 plugin_config *s = p->config_storage[i];
15396 @@ -544,90 +545,87 @@
15397 } else if (s->log_access_fd != -1) {
15398 write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
15402 buffer_reset(s->access_logbuffer);
15406 if (s->use_syslog == 0 &&
15407 !buffer_is_empty(s->access_logfile) &&
15408 s->access_logfile->ptr[0] != '|') {
15411 close(s->log_access_fd);
15413 - if (-1 == (s->log_access_fd =
15415 + if (-1 == (s->log_access_fd =
15416 open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
15419 log_error_write(srv, __FILE__, __LINE__, "ss", "cycling access-log failed:", strerror(errno));
15422 return HANDLER_ERROR;
15428 return HANDLER_GO_ON;
15431 -#define PATCH(x) \
15432 - p->conf.x = s->x;
15433 static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_data *p) {
15435 plugin_config *s = p->config_storage[0];
15437 - PATCH(access_logfile);
15439 - PATCH(log_access_fd);
15440 - PATCH(last_generated_accesslog_ts_ptr);
15441 - PATCH(access_logbuffer);
15442 - PATCH(ts_accesslog_str);
15443 - PATCH(parsed_format);
15444 - PATCH(use_syslog);
15447 + PATCH_OPTION(access_logfile);
15448 + PATCH_OPTION(format);
15449 + PATCH_OPTION(log_access_fd);
15450 + PATCH_OPTION(last_generated_accesslog_ts_ptr);
15451 + PATCH_OPTION(access_logbuffer);
15452 + PATCH_OPTION(ts_accesslog_str);
15453 + PATCH_OPTION(parsed_format);
15454 + PATCH_OPTION(use_syslog);
15456 /* skip the first, the global context */
15457 for (i = 1; i < srv->config_context->used; i++) {
15458 data_config *dc = (data_config *)srv->config_context->data[i];
15459 s = p->config_storage[i];
15462 /* condition didn't match */
15463 if (!config_check_cond(srv, con, dc)) continue;
15467 for (j = 0; j < dc->value->used; j++) {
15468 data_unset *du = dc->value->data[j];
15471 if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.filename"))) {
15472 - PATCH(access_logfile);
15473 - PATCH(log_access_fd);
15474 - PATCH(last_generated_accesslog_ts_ptr);
15475 - PATCH(access_logbuffer);
15476 - PATCH(ts_accesslog_str);
15477 + PATCH_OPTION(access_logfile);
15478 + PATCH_OPTION(log_access_fd);
15479 + PATCH_OPTION(last_generated_accesslog_ts_ptr);
15480 + PATCH_OPTION(access_logbuffer);
15481 + PATCH_OPTION(ts_accesslog_str);
15482 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.format"))) {
15484 - PATCH(parsed_format);
15485 + PATCH_OPTION(format);
15486 + PATCH_OPTION(parsed_format);
15487 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.use-syslog"))) {
15488 - PATCH(use_syslog);
15489 + PATCH_OPTION(use_syslog);
15499 REQUESTDONE_FUNC(log_access_write) {
15500 plugin_data *p = p_d;
15509 mod_accesslog_patch_connection(srv, con, p);
15512 b = p->conf.access_logbuffer;
15513 if (b->used == 0) {
15514 buffer_copy_string(b, "");
15518 for (j = 0; j < p->conf.parsed_format->used; j++) {
15519 switch(p->conf.parsed_format->ptr[j]->type) {
15521 @@ -636,14 +634,14 @@
15523 switch(p->conf.parsed_format->ptr[j]->field) {
15524 case FORMAT_TIMESTAMP:
15527 /* cache the generated timestamp */
15528 if (srv->cur_ts != *(p->conf.last_generated_accesslog_ts_ptr)) {
15530 #if defined(HAVE_STRUCT_TM_GMTOFF)
15531 long scd, hrs, min;
15535 buffer_prepare_copy(p->conf.ts_accesslog_str, 255);
15536 #if defined(HAVE_STRUCT_TM_GMTOFF)
15537 # ifdef HAVE_LOCALTIME_R
15538 @@ -653,17 +651,17 @@
15539 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)));
15541 p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
15544 buffer_append_string(p->conf.ts_accesslog_str, tm.tm_gmtoff >= 0 ? "+" : "-");
15547 scd = abs(tm.tm_gmtoff);
15549 min = (scd % 3600) / 60;
15553 if (hrs < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
15554 buffer_append_long(p->conf.ts_accesslog_str, hrs);
15557 if (min < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
15558 buffer_append_long(p->conf.ts_accesslog_str, min);
15559 BUFFER_APPEND_STRING_CONST(p->conf.ts_accesslog_str, "]");
15560 @@ -676,20 +674,20 @@
15562 p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
15566 *(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts;
15571 buffer_append_string_buffer(b, p->conf.ts_accesslog_str);
15575 case FORMAT_REMOTE_HOST:
15578 /* handle inet_ntop cache */
15581 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
15585 case FORMAT_REMOTE_IDENT:
15587 @@ -710,10 +708,10 @@
15588 case FORMAT_STATUS:
15589 buffer_append_long(b, con->http_status);
15593 case FORMAT_BYTES_OUT_NO_HEADER:
15594 if (con->bytes_written > 0) {
15595 - buffer_append_off_t(b,
15596 + buffer_append_off_t(b,
15597 con->bytes_written - con->bytes_header <= 0 ? 0 : con->bytes_written - con->bytes_header);
15599 BUFFER_APPEND_STRING_CONST(b, "-");
15600 @@ -772,7 +770,7 @@
15603 case FORMAT_REQUEST_PROTOCOL:
15604 - buffer_append_string(b,
15605 + buffer_append_string(b,
15606 con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0");
15608 case FORMAT_REQUEST_METHOD:
15609 @@ -801,7 +799,7 @@
15610 { 'D', FORMAT_TIME_USED_MS },
15611 { 'e', FORMAT_ENV },
15618 @@ -809,7 +807,7 @@
15624 BUFFER_APPEND_STRING_CONST(b, "\n");
15626 if (p->conf.use_syslog || /* syslog doesn't cache */
15627 @@ -828,7 +826,7 @@
15633 return HANDLER_GO_ON;
15636 @@ -836,15 +834,15 @@
15637 int mod_accesslog_plugin_init(plugin *p) {
15638 p->version = LIGHTTPD_VERSION_ID;
15639 p->name = buffer_init_string("accesslog");
15642 p->init = mod_accesslog_init;
15643 p->set_defaults= log_access_open;
15644 p->cleanup = mod_accesslog_free;
15647 p->handle_request_done = log_access_write;
15648 p->handle_sighup = log_access_cycle;
15656 --- ../lighttpd-1.4.11/src/mod_alias.c 2006-03-01 23:18:51.000000000 +0200
15657 +++ lighttpd-1.4.12/src/mod_alias.c 2006-07-16 00:26:03.000000000 +0300
15659 #include "buffer.h"
15661 #include "plugin.h"
15662 +#include "sys-strings.h"
15664 /* plugin config for all request/connections */
15666 @@ -16,44 +17,44 @@
15672 plugin_config **config_storage;
15674 - plugin_config conf;
15676 + plugin_config conf;
15679 /* init the plugin data */
15680 INIT_FUNC(mod_alias_init) {
15684 p = calloc(1, sizeof(*p));
15694 /* detroy the plugin data */
15695 FREE_FUNC(mod_alias_free) {
15696 plugin_data *p = p_d;
15699 if (!p) return HANDLER_GO_ON;
15702 if (p->config_storage) {
15706 for (i = 0; i < srv->config_context->used; i++) {
15707 plugin_config *s = p->config_storage[i];
15710 array_free(s->alias);
15715 free(p->config_storage);
15722 return HANDLER_GO_ON;
15725 @@ -62,25 +63,25 @@
15726 SETDEFAULTS_FUNC(mod_alias_set_defaults) {
15727 plugin_data *p = p_d;
15730 - config_values_t cv[] = {
15732 + config_values_t cv[] = {
15733 { "alias.url", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
15734 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
15738 if (!p) return HANDLER_ERROR;
15741 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
15744 for (i = 0; i < srv->config_context->used; i++) {
15748 s = calloc(1, sizeof(plugin_config));
15749 - s->alias = array_init();
15750 + s->alias = array_init();
15751 cv[0].destination = s->alias;
15754 p->config_storage[i] = s;
15757 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
15758 return HANDLER_ERROR;
15760 @@ -110,76 +111,73 @@
15766 return HANDLER_GO_ON;
15769 -#define PATCH(x) \
15770 - p->conf.x = s->x;
15771 static int mod_alias_patch_connection(server *srv, connection *con, plugin_data *p) {
15773 plugin_config *s = p->config_storage[0];
15778 + PATCH_OPTION(alias);
15780 /* skip the first, the global context */
15781 for (i = 1; i < srv->config_context->used; i++) {
15782 data_config *dc = (data_config *)srv->config_context->data[i];
15783 s = p->config_storage[i];
15786 /* condition didn't match */
15787 if (!config_check_cond(srv, con, dc)) continue;
15791 for (j = 0; j < dc->value->used; j++) {
15792 data_unset *du = dc->value->data[j];
15795 if (buffer_is_equal_string(du->key, CONST_STR_LEN("alias.url"))) {
15797 + PATCH_OPTION(alias);
15807 PHYSICALPATH_FUNC(mod_alias_physical_handler) {
15808 plugin_data *p = p_d;
15809 int uri_len, basedir_len;
15814 if (con->physical.path->used == 0) return HANDLER_GO_ON;
15817 mod_alias_patch_connection(srv, con, p);
15820 /* not to include the tailing slash */
15821 basedir_len = (con->physical.basedir->used - 1) - 1;
15822 uri_len = con->physical.path->used - 1 - basedir_len;
15823 uri_ptr = con->physical.path->ptr + basedir_len;
15826 for (k = 0; k < p->conf.alias->used; k++) {
15827 data_string *ds = (data_string *)p->conf.alias->data[k];
15828 int alias_len = ds->key->used - 1;
15831 if (alias_len > uri_len) continue;
15832 if (ds->key->used == 0) continue;
15835 if (0 == (con->conf.force_lowercase_filenames ?
15836 strncasecmp(uri_ptr, ds->key->ptr, alias_len) :
15837 strncmp(uri_ptr, ds->key->ptr, alias_len))) {
15841 buffer_copy_string_buffer(con->physical.basedir, ds->value);
15842 buffer_copy_string_buffer(srv->tmp_buf, ds->value);
15843 buffer_append_string(srv->tmp_buf, uri_ptr + alias_len);
15844 buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
15847 return HANDLER_GO_ON;
15853 return HANDLER_GO_ON;
15855 @@ -189,13 +187,13 @@
15856 int mod_alias_plugin_init(plugin *p) {
15857 p->version = LIGHTTPD_VERSION_ID;
15858 p->name = buffer_init_string("alias");
15861 p->init = mod_alias_init;
15862 p->handle_physical= mod_alias_physical_handler;
15863 p->set_defaults = mod_alias_set_defaults;
15864 p->cleanup = mod_alias_free;
15872 --- ../lighttpd-1.4.11/src/mod_auth.c 2006-02-15 20:01:31.000000000 +0200
15873 +++ lighttpd-1.4.12/src/mod_auth.c 2006-07-18 13:03:40.000000000 +0300
15874 @@ -5,168 +5,167 @@
15875 #include <string.h>
15878 -#include <unistd.h>
15880 #include "plugin.h"
15881 #include "http_auth.h"
15883 #include "response.h"
15885 +#include "sys-strings.h"
15886 +#include "sys-files.h"
15888 handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
15892 * the basic and digest auth framework
15895 * - config handling
15896 * - protocol handling
15899 - * http_auth_digest.c
15903 + * http_auth_digest.c
15908 INIT_FUNC(mod_auth_init) {
15909 mod_auth_plugin_data *p;
15912 p = calloc(1, sizeof(*p));
15915 p->tmp_buf = buffer_init();
15918 p->auth_user = buffer_init();
15920 p->ldap_filter = buffer_init();
15927 FREE_FUNC(mod_auth_free) {
15928 mod_auth_plugin_data *p = p_d;
15933 if (!p) return HANDLER_GO_ON;
15936 buffer_free(p->tmp_buf);
15937 buffer_free(p->auth_user);
15939 buffer_free(p->ldap_filter);
15943 if (p->config_storage) {
15945 for (i = 0; i < srv->config_context->used; i++) {
15946 mod_auth_plugin_config *s = p->config_storage[i];
15952 array_free(s->auth_require);
15953 buffer_free(s->auth_plain_groupfile);
15954 buffer_free(s->auth_plain_userfile);
15955 buffer_free(s->auth_htdigest_userfile);
15956 buffer_free(s->auth_htpasswd_userfile);
15957 buffer_free(s->auth_backend_conf);
15960 buffer_free(s->auth_ldap_hostname);
15961 buffer_free(s->auth_ldap_basedn);
15962 buffer_free(s->auth_ldap_binddn);
15963 buffer_free(s->auth_ldap_bindpw);
15964 buffer_free(s->auth_ldap_filter);
15965 buffer_free(s->auth_ldap_cafile);
15969 buffer_free(s->ldap_filter_pre);
15970 buffer_free(s->ldap_filter_post);
15973 if (s->ldap) ldap_unbind_s(s->ldap);
15979 free(p->config_storage);
15986 return HANDLER_GO_ON;
15989 -#define PATCH(x) \
15990 - p->conf.x = s->x;
15991 static int mod_auth_patch_connection(server *srv, connection *con, mod_auth_plugin_data *p) {
15993 mod_auth_plugin_config *s = p->config_storage[0];
15995 - PATCH(auth_backend);
15996 - PATCH(auth_plain_groupfile);
15997 - PATCH(auth_plain_userfile);
15998 - PATCH(auth_htdigest_userfile);
15999 - PATCH(auth_htpasswd_userfile);
16000 - PATCH(auth_require);
16001 - PATCH(auth_debug);
16002 - PATCH(auth_ldap_hostname);
16003 - PATCH(auth_ldap_basedn);
16004 - PATCH(auth_ldap_binddn);
16005 - PATCH(auth_ldap_bindpw);
16006 - PATCH(auth_ldap_filter);
16007 - PATCH(auth_ldap_cafile);
16008 - PATCH(auth_ldap_starttls);
16009 + PATCH_OPTION(auth_backend);
16010 + PATCH_OPTION(auth_plain_groupfile);
16011 + PATCH_OPTION(auth_plain_userfile);
16012 + PATCH_OPTION(auth_htdigest_userfile);
16013 + PATCH_OPTION(auth_htpasswd_userfile);
16014 + PATCH_OPTION(auth_require);
16015 + PATCH_OPTION(auth_debug);
16016 + PATCH_OPTION(auth_ldap_hostname);
16017 + PATCH_OPTION(auth_ldap_basedn);
16018 + PATCH_OPTION(auth_ldap_binddn);
16019 + PATCH_OPTION(auth_ldap_bindpw);
16020 + PATCH_OPTION(auth_ldap_filter);
16021 + PATCH_OPTION(auth_ldap_cafile);
16022 + PATCH_OPTION(auth_ldap_starttls);
16025 - PATCH(ldap_filter_pre);
16026 - PATCH(ldap_filter_post);
16027 + PATCH_OPTION(ldap);
16028 + PATCH_OPTION(ldap_filter_pre);
16029 + PATCH_OPTION(ldap_filter_post);
16033 /* skip the first, the global context */
16034 for (i = 1; i < srv->config_context->used; i++) {
16035 data_config *dc = (data_config *)srv->config_context->data[i];
16036 s = p->config_storage[i];
16039 /* condition didn't match */
16040 if (!config_check_cond(srv, con, dc)) continue;
16044 for (j = 0; j < dc->value->used; j++) {
16045 data_unset *du = dc->value->data[j];
16048 if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend"))) {
16049 - PATCH(auth_backend);
16050 + PATCH_OPTION(auth_backend);
16051 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.groupfile"))) {
16052 - PATCH(auth_plain_groupfile);
16053 + PATCH_OPTION(auth_plain_groupfile);
16054 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.userfile"))) {
16055 - PATCH(auth_plain_userfile);
16056 + PATCH_OPTION(auth_plain_userfile);
16057 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htdigest.userfile"))) {
16058 - PATCH(auth_htdigest_userfile);
16059 + PATCH_OPTION(auth_htdigest_userfile);
16060 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htpasswd.userfile"))) {
16061 - PATCH(auth_htpasswd_userfile);
16062 + PATCH_OPTION(auth_htpasswd_userfile);
16063 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.require"))) {
16064 - PATCH(auth_require);
16065 + PATCH_OPTION(auth_require);
16066 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.debug"))) {
16067 - PATCH(auth_debug);
16068 + PATCH_OPTION(auth_debug);
16069 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.hostname"))) {
16070 - PATCH(auth_ldap_hostname);
16071 + PATCH_OPTION(auth_ldap_hostname);
16074 - PATCH(ldap_filter_pre);
16075 - PATCH(ldap_filter_post);
16076 + PATCH_OPTION(ldap);
16077 + PATCH_OPTION(ldap_filter_pre);
16078 + PATCH_OPTION(ldap_filter_post);
16080 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.base-dn"))) {
16081 - PATCH(auth_ldap_basedn);
16082 + PATCH_OPTION(auth_ldap_basedn);
16083 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) {
16084 - PATCH(auth_ldap_filter);
16085 + PATCH_OPTION(auth_ldap_filter);
16086 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.ca-file"))) {
16087 - PATCH(auth_ldap_cafile);
16088 + PATCH_OPTION(auth_ldap_cafile);
16089 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.starttls"))) {
16090 - PATCH(auth_ldap_starttls);
16091 + PATCH_OPTION(auth_ldap_starttls);
16101 static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
16103 @@ -175,22 +174,22 @@
16105 mod_auth_plugin_data *p = p_d;
16109 /* select the right config */
16110 mod_auth_patch_connection(srv, con, p);
16113 if (p->conf.auth_require == NULL) return HANDLER_GO_ON;
16123 /* do we have to ask for auth ? */
16127 auth_satisfied = 0;
16130 /* search auth-directives for path */
16131 for (k = 0; k < p->conf.auth_require->used; k++) {
16132 buffer *req = p->conf.auth_require->data[k]->key;
16133 @@ -212,76 +211,76 @@
16139 /* nothing to do for us */
16140 if (auth_required == 0) return HANDLER_GO_ON;
16143 req = ((data_array *)(p->conf.auth_require->data[k]))->value;
16146 /* try to get Authorization-header */
16149 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization"))) {
16150 http_authorization = ds->value->ptr;
16154 if (ds && ds->value && ds->value->used) {
16156 data_string *method;
16159 method = (data_string *)array_get_element(req, "method");
16162 /* parse auth-header */
16163 if (NULL != (auth_realm = strchr(http_authorization, ' '))) {
16164 int auth_type_len = auth_realm - http_authorization;
16167 if ((auth_type_len == 5) &&
16168 (0 == strncmp(http_authorization, "Basic", auth_type_len))) {
16170 - if (0 == strcmp(method->value->ptr, "basic")) {
16172 + if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
16173 auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1);
16175 } else if ((auth_type_len == 6) &&
16176 (0 == strncmp(http_authorization, "Digest", auth_type_len))) {
16177 - if (0 == strcmp(method->value->ptr, "digest")) {
16178 + if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
16179 if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) {
16180 con->http_status = 400;
16183 /* a field was missing */
16186 return HANDLER_FINISHED;
16190 - log_error_write(srv, __FILE__, __LINE__, "ss",
16191 + log_error_write(srv, __FILE__, __LINE__, "ss",
16192 "unknown authentification type:",
16193 http_authorization);
16199 if (!auth_satisfied) {
16200 data_string *method, *realm;
16201 method = (data_string *)array_get_element(req, "method");
16202 realm = (data_string *)array_get_element(req, "realm");
16205 con->http_status = 401;
16207 - if (0 == strcmp(method->value->ptr, "basic")) {
16209 + if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
16210 buffer_copy_string(p->tmp_buf, "Basic realm=\"");
16211 buffer_append_string_buffer(p->tmp_buf, realm->value);
16212 buffer_append_string(p->tmp_buf, "\"");
16215 response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
16216 - } else if (0 == strcmp(method->value->ptr, "digest")) {
16217 + } else if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
16219 http_auth_digest_generate_nonce(srv, p, srv->tmp_buf, hh);
16222 buffer_copy_string(p->tmp_buf, "Digest realm=\"");
16223 buffer_append_string_buffer(p->tmp_buf, realm->value);
16224 buffer_append_string(p->tmp_buf, "\", nonce=\"");
16225 buffer_append_string(p->tmp_buf, hh);
16226 buffer_append_string(p->tmp_buf, "\", qop=\"auth\"");
16229 response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
16232 @@ -289,18 +288,18 @@
16233 return HANDLER_FINISHED;
16235 /* the REMOTE_USER header */
16238 buffer_copy_string_buffer(con->authed_user, p->auth_user);
16242 return HANDLER_GO_ON;
16245 SETDEFAULTS_FUNC(mod_auth_set_defaults) {
16246 mod_auth_plugin_data *p = p_d;
16249 - config_values_t cv[] = {
16251 + config_values_t cv[] = {
16252 { "auth.backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
16253 { "auth.backend.plain.groupfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
16254 { "auth.backend.plain.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
16255 @@ -317,7 +316,7 @@
16256 { "auth.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
16257 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
16261 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
16263 for (i = 0; i < srv->config_context->used; i++) {
16264 @@ -325,14 +324,14 @@
16270 s = calloc(1, sizeof(mod_auth_plugin_config));
16271 s->auth_plain_groupfile = buffer_init();
16272 s->auth_plain_userfile = buffer_init();
16273 s->auth_htdigest_userfile = buffer_init();
16274 s->auth_htpasswd_userfile = buffer_init();
16275 s->auth_backend_conf = buffer_init();
16278 s->auth_ldap_hostname = buffer_init();
16279 s->auth_ldap_basedn = buffer_init();
16280 s->auth_ldap_binddn = buffer_init();
16281 @@ -341,15 +340,15 @@
16282 s->auth_ldap_cafile = buffer_init();
16283 s->auth_ldap_starttls = 0;
16287 s->auth_require = array_init();
16291 s->ldap_filter_pre = buffer_init();
16292 s->ldap_filter_post = buffer_init();
16297 cv[0].destination = s->auth_backend_conf;
16298 cv[1].destination = s->auth_plain_groupfile;
16299 cv[2].destination = s->auth_plain_userfile;
16300 @@ -364,146 +363,148 @@
16301 cv[11].destination = s->auth_htdigest_userfile;
16302 cv[12].destination = s->auth_htpasswd_userfile;
16303 cv[13].destination = &(s->auth_debug);
16306 p->config_storage[i] = s;
16307 ca = ((data_config *)srv->config_context->data[i])->value;
16310 if (0 != config_insert_values_global(srv, ca, cv)) {
16311 return HANDLER_ERROR;
16314 - if (s->auth_backend_conf->used) {
16315 - if (0 == strcmp(s->auth_backend_conf->ptr, "htpasswd")) {
16317 + if (!buffer_is_empty(s->auth_backend_conf)) {
16318 + if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htpasswd"))) {
16319 s->auth_backend = AUTH_BACKEND_HTPASSWD;
16320 - } else if (0 == strcmp(s->auth_backend_conf->ptr, "htdigest")) {
16321 + } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htdigest"))) {
16322 s->auth_backend = AUTH_BACKEND_HTDIGEST;
16323 - } else if (0 == strcmp(s->auth_backend_conf->ptr, "plain")) {
16324 + } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("plain"))) {
16325 s->auth_backend = AUTH_BACKEND_PLAIN;
16326 - } else if (0 == strcmp(s->auth_backend_conf->ptr, "ldap")) {
16327 + } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("ldap"))) {
16328 s->auth_backend = AUTH_BACKEND_LDAP;
16330 log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf);
16333 return HANDLER_ERROR;
16337 /* no auth.require for this section */
16338 if (NULL == (da = (data_array *)array_get_element(ca, "auth.require"))) continue;
16341 if (da->type != TYPE_ARRAY) continue;
16344 for (n = 0; n < da->value->used; n++) {
16346 data_array *da_file = (data_array *)da->value->data[n];
16347 - const char *method, *realm, *require;
16349 + buffer *method, *realm, *require;
16351 if (da->value->data[n]->type != TYPE_ARRAY) {
16352 - log_error_write(srv, __FILE__, __LINE__, "ss",
16353 - "auth.require should contain an array as in:",
16354 + log_error_write(srv, __FILE__, __LINE__, "ss",
16355 + "auth.require should contain an array as in:",
16356 "auth.require = ( \"...\" => ( ..., ...) )");
16358 return HANDLER_ERROR;
16362 method = realm = require = NULL;
16365 for (m = 0; m < da_file->value->used; m++) {
16366 - if (da_file->value->data[m]->type == TYPE_STRING) {
16367 - if (0 == strcmp(da_file->value->data[m]->key->ptr, "method")) {
16368 - method = ((data_string *)(da_file->value->data[m]))->value->ptr;
16369 - } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "realm")) {
16370 - realm = ((data_string *)(da_file->value->data[m]))->value->ptr;
16371 - } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "require")) {
16372 - require = ((data_string *)(da_file->value->data[m]))->value->ptr;
16374 - log_error_write(srv, __FILE__, __LINE__, "ssbs",
16375 - "the field is unknown in:",
16376 + data_string *ds_auth_req = (data_string *)da_file->value->data[m];
16378 + if (ds_auth_req->type != TYPE_STRING) {
16379 + log_error_write(srv, __FILE__, __LINE__, "ssbs",
16380 + "a string was expected for:",
16381 + "auth.require = ( \"...\" => ( ..., -> \"",
16382 + ds_auth_req->key,
16383 + "\" <- => \"...\" ) )");
16385 + return HANDLER_ERROR;
16388 + if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("method"))) {
16389 + method = ds_auth_req->value;
16390 + } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("realm"))) {
16391 + realm = ds_auth_req->value;
16392 + } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("require"))) {
16393 + require = ds_auth_req->value;
16395 + log_error_write(srv, __FILE__, __LINE__, "ssbs",
16396 + "the field is unknown in:",
16397 "auth.require = ( \"...\" => ( ..., -> \"",
16398 da_file->value->data[m]->key,
16399 "\" <- => \"...\" ) )");
16401 - return HANDLER_ERROR;
16404 - log_error_write(srv, __FILE__, __LINE__, "ssbs",
16405 - "a string was expected for:",
16406 - "auth.require = ( \"...\" => ( ..., -> \"",
16407 - da_file->value->data[m]->key,
16408 - "\" <- => \"...\" ) )");
16410 return HANDLER_ERROR;
16416 if (method == NULL) {
16417 - log_error_write(srv, __FILE__, __LINE__, "ss",
16418 - "the require field is missing in:",
16419 + log_error_write(srv, __FILE__, __LINE__, "ss",
16420 + "the require field is missing in:",
16421 "auth.require = ( \"...\" => ( ..., \"method\" => \"...\" ) )");
16422 return HANDLER_ERROR;
16424 - if (0 != strcmp(method, "basic") &&
16425 - 0 != strcmp(method, "digest")) {
16426 - log_error_write(srv, __FILE__, __LINE__, "ss",
16427 - "method has to be either \"basic\" or \"digest\" in",
16428 - "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
16429 - return HANDLER_ERROR;
16432 + if (!buffer_is_equal_string(method, CONST_STR_LEN("basic")) &&
16433 + !buffer_is_equal_string(method, CONST_STR_LEN("digest"))) {
16434 + log_error_write(srv, __FILE__, __LINE__, "ss",
16435 + "method has to be either \"basic\" or \"digest\" in",
16436 + "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
16437 + return HANDLER_ERROR;
16441 if (realm == NULL) {
16442 - log_error_write(srv, __FILE__, __LINE__, "ss",
16443 - "the require field is missing in:",
16444 + log_error_write(srv, __FILE__, __LINE__, "ss",
16445 + "the require field is missing in:",
16446 "auth.require = ( \"...\" => ( ..., \"realm\" => \"...\" ) )");
16447 return HANDLER_ERROR;
16451 if (require == NULL) {
16452 - log_error_write(srv, __FILE__, __LINE__, "ss",
16453 - "the require field is missing in:",
16454 + log_error_write(srv, __FILE__, __LINE__, "ss",
16455 + "the require field is missing in:",
16456 "auth.require = ( \"...\" => ( ..., \"require\" => \"...\" ) )");
16457 return HANDLER_ERROR;
16461 if (method && realm && require) {
16466 a = data_array_init();
16467 buffer_copy_string_buffer(a->key, da_file->key);
16470 ds = data_string_init();
16473 buffer_copy_string(ds->key, "method");
16474 - buffer_copy_string(ds->value, method);
16476 + buffer_copy_string_buffer(ds->value, method);
16478 array_insert_unique(a->value, (data_unset *)ds);
16481 ds = data_string_init();
16484 buffer_copy_string(ds->key, "realm");
16485 - buffer_copy_string(ds->value, realm);
16487 + buffer_copy_string_buffer(ds->value, realm);
16489 array_insert_unique(a->value, (data_unset *)ds);
16492 ds = data_string_init();
16495 buffer_copy_string(ds->key, "require");
16496 - buffer_copy_string(ds->value, require);
16498 + buffer_copy_string_buffer(ds->value, require);
16500 array_insert_unique(a->value, (data_unset *)ds);
16503 array_insert_unique(s->auth_require, (data_unset *)a);
16508 switch(s->auth_backend) {
16509 case AUTH_BACKEND_PLAIN:
16510 if (s->auth_plain_userfile->used) {
16513 if (-1 == (fd = open(s->auth_plain_userfile->ptr, O_RDONLY))) {
16514 - log_error_write(srv, __FILE__, __LINE__, "sbss",
16515 + log_error_write(srv, __FILE__, __LINE__, "sbss",
16516 "opening auth.backend.plain.userfile:", s->auth_plain_userfile,
16517 "failed:", strerror(errno));
16518 return HANDLER_ERROR;
16519 @@ -516,7 +517,7 @@
16522 if (-1 == (fd = open(s->auth_htpasswd_userfile->ptr, O_RDONLY))) {
16523 - log_error_write(srv, __FILE__, __LINE__, "sbss",
16524 + log_error_write(srv, __FILE__, __LINE__, "sbss",
16525 "opening auth.backend.htpasswd.userfile:", s->auth_htpasswd_userfile,
16526 "failed:", strerror(errno));
16527 return HANDLER_ERROR;
16528 @@ -529,7 +530,7 @@
16531 if (-1 == (fd = open(s->auth_htdigest_userfile->ptr, O_RDONLY))) {
16532 - log_error_write(srv, __FILE__, __LINE__, "sbss",
16533 + log_error_write(srv, __FILE__, __LINE__, "sbss",
16534 "opening auth.backend.htdigest.userfile:", s->auth_htdigest_userfile,
16535 "failed:", strerror(errno));
16536 return HANDLER_ERROR;
16537 @@ -554,75 +555,75 @@
16538 handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s) {
16543 if (s->auth_ldap_basedn->used == 0) {
16544 log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.base-dn has to be set");
16547 return HANDLER_ERROR;
16552 if (s->auth_ldap_filter->used) {
16559 if (NULL == (dollar = strchr(s->auth_ldap_filter->ptr, '$'))) {
16560 log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '$'");
16563 return HANDLER_ERROR;
16567 buffer_copy_string_len(s->ldap_filter_pre, s->auth_ldap_filter->ptr, dollar - s->auth_ldap_filter->ptr);
16568 buffer_copy_string(s->ldap_filter_post, dollar+1);
16572 if (s->auth_ldap_hostname->used) {
16573 if (NULL == (s->ldap = ldap_init(s->auth_ldap_hostname->ptr, LDAP_PORT))) {
16574 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
16577 return HANDLER_ERROR;
16581 ret = LDAP_VERSION3;
16582 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(s->ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
16583 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16586 return HANDLER_ERROR;
16589 if (s->auth_ldap_starttls) {
16590 - /* if no CA file is given, it is ok, as we will use encryption
16591 + /* if no CA file is given, it is ok, as we will use encryption
16592 * if the server requires a CAfile it will tell us */
16593 if (!buffer_is_empty(s->auth_ldap_cafile)) {
16594 - if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
16595 + if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
16596 s->auth_ldap_cafile->ptr))) {
16597 - log_error_write(srv, __FILE__, __LINE__, "ss",
16598 + log_error_write(srv, __FILE__, __LINE__, "ss",
16599 "Loading CA certificate failed:", ldap_err2string(ret));
16602 return HANDLER_ERROR;
16607 if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(s->ldap, NULL, NULL))) {
16608 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
16611 return HANDLER_ERROR;
16619 if (s->auth_ldap_binddn->used) {
16620 if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, s->auth_ldap_binddn->ptr, s->auth_ldap_bindpw->ptr))) {
16621 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16624 return HANDLER_ERROR;
16627 if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, NULL, NULL))) {
16628 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16631 return HANDLER_ERROR;
16634 @@ -641,8 +642,8 @@
16635 p->set_defaults = mod_auth_set_defaults;
16636 p->handle_uri_clean = mod_auth_uri_handler;
16637 p->cleanup = mod_auth_free;
16645 --- ../lighttpd-1.4.11/src/mod_cgi.c 2006-02-22 15:15:10.000000000 +0200
16646 +++ lighttpd-1.4.12/src/mod_cgi.c 2006-07-18 17:34:32.000000000 +0300
16648 #include <sys/types.h>
16650 -#include <winsock2.h>
16652 -#include <sys/socket.h>
16653 -#include <sys/wait.h>
16654 -#include <sys/mman.h>
16656 -#include <netinet/in.h>
16658 -#include <arpa/inet.h>
16661 -#include <unistd.h>
16663 #include <stdlib.h>
16664 #include <string.h>
16665 -#include <fdevent.h>
16666 #include <signal.h>
16668 #include <assert.h>
16670 #include "connections.h"
16671 #include "joblist.h"
16672 #include "http_chunk.h"
16673 +#include "fdevent.h"
16675 #include "plugin.h"
16676 +#include "http_resp.h"
16678 +#include "sys-files.h"
16679 +#include "sys-mmap.h"
16680 +#include "sys-socket.h"
16681 +#include "sys-strings.h"
16682 +#include "sys-process.h"
16684 #ifdef HAVE_SYS_FILIO_H
16685 # include <sys/filio.h>
16686 @@ -40,11 +35,12 @@
16700 @@ -58,57 +54,68 @@
16703 buffer_pid_t cgi_pid;
16707 - buffer *parse_response;
16712 plugin_config **config_storage;
16714 - plugin_config conf;
16716 + plugin_config conf;
16721 + CGI_STATE_CONNECTING,
16722 + CGI_STATE_READ_RESPONSE_HEADER,
16723 + CGI_STATE_READ_RESPONSE_CONTENT
16729 - int fde_ndx; /* index into the fd-event buffer */
16731 - connection *remote_conn; /* dumb pointer */
16732 - plugin_data *plugin_data; /* dumb pointer */
16734 - buffer *response;
16735 - buffer *response_header;
16738 -static handler_ctx * cgi_handler_ctx_init() {
16739 - handler_ctx *hctx = calloc(1, sizeof(*hctx));
16744 - hctx->response = buffer_init();
16745 - hctx->response_header = buffer_init();
16752 -static void cgi_handler_ctx_free(handler_ctx *hctx) {
16753 - buffer_free(hctx->response);
16754 - buffer_free(hctx->response_header);
16757 + cgi_state_t state;
16759 + connection *remote_con; /* dumb pointer */
16762 +static cgi_session * cgi_session_init() {
16763 + cgi_session *sess = calloc(1, sizeof(*sess));
16766 + sess->sock = iosocket_init();
16767 + sess->wb = chunkqueue_init();
16768 + sess->rb = chunkqueue_init();
16773 -enum {FDEVENT_HANDLED_UNSET, FDEVENT_HANDLED_FINISHED, FDEVENT_HANDLED_NOT_FINISHED, FDEVENT_HANDLED_ERROR};
16774 +static void cgi_session_free(cgi_session *sess) {
16775 + if (!sess) return;
16777 + iosocket_free(sess->sock);
16779 + chunkqueue_free(sess->wb);
16780 + chunkqueue_free(sess->rb);
16785 INIT_FUNC(mod_cgi_init) {
16789 p = calloc(1, sizeof(*p));
16794 p->tmp_buf = buffer_init();
16795 - p->parse_response = buffer_init();
16797 + p->resp = http_response_init();
16802 @@ -116,62 +123,62 @@
16803 FREE_FUNC(mod_cgi_free) {
16804 plugin_data *p = p_d;
16805 buffer_pid_t *r = &(p->cgi_pid);
16811 if (p->config_storage) {
16813 for (i = 0; i < srv->config_context->used; i++) {
16814 plugin_config *s = p->config_storage[i];
16817 array_free(s->cgi);
16822 free(p->config_storage);
16827 if (r->ptr) free(r->ptr);
16830 buffer_free(p->tmp_buf);
16831 - buffer_free(p->parse_response);
16833 + http_response_free(p->resp);
16838 return HANDLER_GO_ON;
16841 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
16842 plugin_data *p = p_d;
16845 - config_values_t cv[] = {
16847 + config_values_t cv[] = {
16848 { "cgi.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
16849 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET}
16852 if (!p) return HANDLER_ERROR;
16855 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
16858 for (i = 0; i < srv->config_context->used; i++) {
16862 s = calloc(1, sizeof(plugin_config));
16866 s->cgi = array_init();
16869 cv[0].destination = s->cgi;
16872 p->config_storage[i] = s;
16875 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
16876 return HANDLER_ERROR;
16881 return HANDLER_GO_ON;
16884 @@ -180,13 +187,13 @@
16887 buffer_pid_t *r = &(p->cgi_pid);
16892 for (i = 0; i < r->used; i++) {
16893 if (r->ptr[i] > m) m = r->ptr[i];
16897 if (r->size == 0) {
16899 r->ptr = malloc(sizeof(*r->ptr) * r->size);
16900 @@ -194,321 +201,179 @@
16902 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
16906 r->ptr[r->used++] = pid;
16912 static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) {
16914 buffer_pid_t *r = &(p->cgi_pid);
16919 for (i = 0; i < r->used; i++) {
16920 if (r->ptr[i] == pid) break;
16924 if (i != r->used) {
16928 if (i != r->used - 1) {
16929 r->ptr[i] = r->ptr[r->used - 1];
16938 -static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
16945 - buffer_copy_string_buffer(p->parse_response, in);
16947 - for (s = p->parse_response->ptr;
16948 - NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n')));
16949 - s = ns + (eol == EOL_RN ? 2 : 1), line++) {
16950 - const char *key, *value;
16957 - 0 == strncmp(s, "HTTP/1.", 7)) {
16958 - /* non-parsed header ... we parse them anyway */
16960 - if ((s[7] == '1' ||
16964 - /* after the space should be a status code for us */
16966 - status = strtol(s+9, NULL, 10);
16968 - if (con->http_status >= 100 &&
16969 - con->http_status < 1000) {
16970 - /* we expected 3 digits and didn't got them */
16971 - con->parsed_response |= HTTP_STATUS;
16972 - con->http_status = status;
16978 - if (NULL == (value = strchr(s, ':'))) {
16979 - /* we expect: "<key>: <value>\r\n" */
16983 - key_len = value - key;
16987 - while (*value == ' ' || *value == '\t') value++;
16989 - if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
16990 - ds = data_response_init();
16992 - buffer_copy_string_len(ds->key, key, key_len);
16993 - buffer_copy_string(ds->value, value);
16995 - array_insert_unique(con->response.headers, (data_unset *)ds);
16997 - switch(key_len) {
16999 - if (0 == strncasecmp(key, "Date", key_len)) {
17000 - con->parsed_response |= HTTP_DATE;
17004 - if (0 == strncasecmp(key, "Status", key_len)) {
17005 - con->http_status = strtol(value, NULL, 10);
17006 - con->parsed_response |= HTTP_STATUS;
17010 - if (0 == strncasecmp(key, "Location", key_len)) {
17011 - con->parsed_response |= HTTP_LOCATION;
17015 - if (0 == strncasecmp(key, "Connection", key_len)) {
17016 - con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
17017 - con->parsed_response |= HTTP_CONNECTION;
17021 - if (0 == strncasecmp(key, "Content-Length", key_len)) {
17022 - con->response.content_length = strtol(value, NULL, 10);
17023 - con->parsed_response |= HTTP_CONTENT_LENGTH;
17032 - /* CGI/1.1 rev 03 - 7.2.1.2 */
17033 - if ((con->parsed_response & HTTP_LOCATION) &&
17034 - !(con->parsed_response & HTTP_STATUS)) {
17035 - con->http_status = 302;
17036 +static int cgi_demux_response(server *srv, connection *con, plugin_data *p) {
17037 + cgi_session *sess = con->plugin_ctx[p->id];
17040 + switch(srv->network_backend_read(srv, con, sess->sock, sess->rb)) {
17041 + case NETWORK_STATUS_SUCCESS:
17042 + /* we got content */
17044 + case NETWORK_STATUS_WAIT_FOR_EVENT:
17046 + case NETWORK_STATUS_CONNECTION_CLOSE:
17047 + /* this is a bit too early */
17048 + ERROR("%s", "cgi-connection got closed before we read the response-header (CGI died ?)");
17052 + ERROR("%s", "oops, read-pipe-read failed and I don't know why");
17059 + /* looks like we got some content
17061 + * split off the header from the incoming stream
17064 -static int cgi_demux_response(server *srv, handler_ctx *hctx) {
17065 - plugin_data *p = hctx->plugin_data;
17066 - connection *con = hctx->remote_conn;
17071 - buffer_prepare_copy(hctx->response, 1024);
17072 - if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
17073 - if (errno == EAGAIN || errno == EINTR) {
17074 - /* would block, wait for signal */
17075 - return FDEVENT_HANDLED_NOT_FINISHED;
17078 - log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
17079 - return FDEVENT_HANDLED_ERROR;
17083 - /* read finished */
17085 - con->file_finished = 1;
17087 - /* send final chunk */
17088 - http_chunk_append_mem(srv, con, NULL, 0);
17089 - joblist_append(srv, con);
17091 - return FDEVENT_HANDLED_FINISHED;
17094 - hctx->response->ptr[n] = '\0';
17095 - hctx->response->used = n+1;
17097 - /* split header from body */
17099 - if (con->file_started == 0) {
17101 - int in_header = 0;
17102 - int header_end = 0;
17103 - int cp, eol = EOL_UNSET;
17106 - buffer_append_string_buffer(hctx->response_header, hctx->response);
17108 - /* nph (non-parsed headers) */
17109 - if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
17111 - /* search for the \r\n\r\n or \n\n in the string */
17112 - for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
17113 - if (*c == ':') in_header = 1;
17114 - else if (*c == '\n') {
17115 - if (in_header == 0) {
17116 - /* got a response without a response header */
17123 - if (eol == EOL_UNSET) eol = EOL_N;
17125 - if (*(c+1) == '\n') {
17130 - } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
17131 - if (in_header == 0) {
17132 - /* got a response without a response header */
17139 - if (eol == EOL_UNSET) eol = EOL_RN;
17142 - *(c+2) == '\r' &&
17143 - *(c+3) == '\n') {
17148 - /* skip the \n */
17152 + if (con->file_started == 0) {
17154 + int have_content_length = 0;
17156 + http_response_reset(p->resp);
17158 + /* the response header is not fully received yet,
17160 + * extract the http-response header from the rb-cq
17162 + switch (http_response_parse_cq(sess->rb, p->resp)) {
17163 + case PARSE_ERROR:
17164 + /* parsing failed */
17166 + TRACE("%s", "response parser failed");
17168 + con->http_status = 502; /* Bad Gateway */
17170 + case PARSE_NEED_MORE:
17172 + case PARSE_SUCCESS:
17173 + con->http_status = p->resp->status;
17175 + chunkqueue_remove_finished_chunks(sess->rb);
17177 + /* copy the http-headers */
17178 + for (i = 0; i < p->resp->headers->used; i++) {
17179 + const char *ign[] = { "Status", "Connection", NULL };
17183 + data_string *header = (data_string *)p->resp->headers->data[i];
17185 + /* some headers are ignored by default */
17186 + for (j = 0; ign[j]; j++) {
17187 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
17191 - if (header_end) {
17193 - /* no header, but a body */
17195 - if (con->request.http_version == HTTP_VERSION_1_1) {
17196 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17199 - http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
17200 - joblist_append(srv, con);
17202 - size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
17203 - size_t blen = hctx->response_header->used - hlen - 1;
17205 - /* a small hack: terminate after at the second \r */
17206 - hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
17207 - hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
17209 - /* parse the response header */
17210 - cgi_response_parse(srv, con, p, hctx->response_header, eol);
17212 - /* enable chunked-transfer-encoding */
17213 - if (con->request.http_version == HTTP_VERSION_1_1 &&
17214 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
17215 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17218 - if ((hctx->response->used != hlen) && blen > 0) {
17219 - http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
17220 - joblist_append(srv, con);
17222 + if (ign[j]) continue;
17224 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
17225 + /* CGI/1.1 rev 03 - 7.2.1.2 */
17226 + if (con->http_status == 0) con->http_status = 302;
17227 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
17228 + have_content_length = 1;
17231 - con->file_started = 1;
17232 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
17233 + ds = data_response_init();
17235 + buffer_copy_string_buffer(ds->key, header->key);
17236 + buffer_copy_string_buffer(ds->value, header->value);
17238 + array_insert_unique(con->response.headers, (data_unset *)ds);
17241 - http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
17242 - joblist_append(srv, con);
17244 + con->file_started = 1;
17245 + sess->state = CGI_STATE_READ_RESPONSE_CONTENT;
17247 + if (con->request.http_version == HTTP_VERSION_1_1 &&
17248 + !have_content_length) {
17249 + con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17256 - log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
17260 - return FDEVENT_HANDLED_NOT_FINISHED;
17262 + /* FIXME: pass the response-header to the other plugins to
17263 + * setup the filter-queue
17265 + * - use next-queue instead of con->write_queue
17268 + /* copy the content to the next cq */
17269 + for (c = sess->rb->first; c; c = c->next) {
17270 + http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
17272 + c->offset = c->mem->used - 1;
17275 + chunkqueue_remove_finished_chunks(sess->rb);
17276 + joblist_append(srv, con);
17281 -static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) {
17282 +static handler_t cgi_connection_close(server *srv, connection *con, plugin_data *p) {
17283 + cgi_session *sess = con->plugin_ctx[p->id];
17289 - if (NULL == hctx) return HANDLER_GO_ON;
17291 - p = hctx->plugin_data;
17292 - con = hctx->remote_conn;
17295 + if (NULL == sess) return HANDLER_GO_ON;
17296 if (con->mode != p->id) return HANDLER_GO_ON;
17302 /* the connection to the browser went away, but we still have a connection
17303 - * to the CGI script
17304 + * to the CGI script
17306 * close cgi-connection
17309 - if (hctx->fd != -1) {
17311 + if (sess->sock->fd != -1) {
17312 /* close connection to the cgi-script */
17313 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
17314 - fdevent_unregister(srv->ev, hctx->fd);
17316 - if (close(hctx->fd)) {
17317 - log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
17321 - hctx->fde_ndx = -1;
17322 + fdevent_event_del(srv->ev, sess->sock);
17323 + fdevent_unregister(srv->ev, sess->sock);
17331 con->plugin_ctx[p->id] = NULL;
17334 /* is this a good idea ? */
17335 - cgi_handler_ctx_free(hctx);
17337 + cgi_session_free(sess);
17340 /* if waitpid hasn't been called by response.c yet, do it here */
17342 /* check if the CGI-script is already gone */
17344 switch(waitpid(pid, &status, WNOHANG)) {
17346 /* not finished yet */
17347 @@ -519,35 +384,35 @@
17350 if (errno == EINTR) break;
17353 - * errno == ECHILD happens if _subrequest catches the process-status before
17356 + * errno == ECHILD happens if _subrequest catches the process-status before
17357 * we have read the response of the cgi process
17361 * -> WAIT_FOR_EVENT
17363 * -> we get here with waitpid == ECHILD
17367 if (errno == ECHILD) return HANDLER_GO_ON;
17370 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
17371 return HANDLER_ERROR;
17373 /* Send an error if we haven't sent any data yet */
17374 if (0 == con->file_started) {
17375 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
17376 - con->http_status = 500;
17377 + if (con->http_status == 0) con->http_status = 500;
17378 con->mode = DIRECT;
17382 if (WIFEXITED(status)) {
17384 log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", pid);
17389 return HANDLER_GO_ON;
17391 log_error_write(srv, __FILE__, __LINE__, "sd", "cgi died, pid:", pid);
17392 @@ -555,122 +420,126 @@
17393 return HANDLER_GO_ON;
17400 kill(pid, SIGTERM);
17403 /* cgi-script is still alive, queue the PID for removal */
17404 cgi_pid_add(srv, p, pid);
17408 return HANDLER_GO_ON;
17411 static handler_t cgi_connection_close_callback(server *srv, connection *con, void *p_d) {
17412 plugin_data *p = p_d;
17414 - return cgi_connection_close(srv, con->plugin_ctx[p->id]);
17416 + return cgi_connection_close(srv, con, p);
17420 static handler_t cgi_handle_fdevent(void *s, void *ctx, int revents) {
17421 server *srv = (server *)s;
17422 - handler_ctx *hctx = ctx;
17423 - connection *con = hctx->remote_conn;
17425 - joblist_append(srv, con);
17427 - if (hctx->fd == -1) {
17428 - log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "invalid cgi-fd");
17430 - return HANDLER_ERROR;
17433 + cgi_session *sess = ctx;
17434 + connection *con = sess->remote_con;
17437 if (revents & FDEVENT_IN) {
17438 - switch (cgi_demux_response(srv, hctx)) {
17439 - case FDEVENT_HANDLED_NOT_FINISHED:
17440 + switch (sess->state) {
17441 + case CGI_STATE_READ_RESPONSE_HEADER:
17442 + /* parse the header and set file-started, the demuxer will care about it */
17443 + joblist_append(srv, con);
17446 - case FDEVENT_HANDLED_FINISHED:
17447 - /* we are done */
17449 + case CGI_STATE_READ_RESPONSE_CONTENT:
17450 + /* just forward the content to the out-going queue */
17452 + chunkqueue_remove_finished_chunks(sess->rb);
17454 + switch (srv->network_backend_read(srv, sess->remote_con, sess->sock, sess->rb)) {
17455 + case NETWORK_STATUS_CONNECTION_CLOSE:
17456 + fdevent_event_del(srv->ev, sess->sock);
17458 + /* the connection is gone
17459 + * make the connect */
17460 + sess->remote_con->file_finished = 1;
17462 - log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "finished");
17463 + fdevent_event_del(srv->ev, sess->sock);
17465 - cgi_connection_close(srv, hctx);
17467 - /* if we get a IN|HUP and have read everything don't exec the close twice */
17468 - return HANDLER_FINISHED;
17469 - case FDEVENT_HANDLED_ERROR:
17470 - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
17471 - con->http_status = 500;
17472 - con->mode = DIRECT;
17474 - log_error_write(srv, __FILE__, __LINE__, "s", "demuxer failed: ");
17475 + case NETWORK_STATUS_SUCCESS:
17476 + /* read even more, do we have all the content */
17478 + /* how much do we want to read ? */
17480 + /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
17482 + chunkqueue_remove_finished_chunks(sess->rb);
17484 + /* copy the content to the next cq */
17485 + for (c = sess->rb->first; c; c = c->next) {
17486 + if (c->mem->used == 0) continue;
17488 + http_chunk_append_mem(srv, sess->remote_con, c->mem->ptr + c->offset, c->mem->used - c->offset);
17490 + c->offset = c->mem->used - 1;
17493 + chunkqueue_remove_finished_chunks(sess->rb);
17495 + if (sess->remote_con->file_finished) {
17496 + /* send final HTTP-Chunk packet */
17497 + http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
17502 + ERROR("%s", "oops, we failed to read");
17506 + joblist_append(srv, sess->remote_con);
17509 + TRACE("unexpected state for a FDEVENT_IN: %d", sess->state);
17515 if (revents & FDEVENT_OUT) {
17516 /* nothing to do */
17520 /* perhaps this issue is already handled */
17521 if (revents & FDEVENT_HUP) {
17522 - /* check if we still have a unfinished header package which is a body in reality */
17523 - if (con->file_started == 0 &&
17524 - hctx->response_header->used) {
17525 - con->file_started = 1;
17526 - http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
17527 - joblist_append(srv, con);
17530 - if (con->file_finished == 0) {
17531 - http_chunk_append_mem(srv, con, NULL, 0);
17532 - joblist_append(srv, con);
17535 con->file_finished = 1;
17537 - if (chunkqueue_is_empty(con->write_queue)) {
17538 - /* there is nothing left to write */
17539 - connection_set_state(srv, con, CON_STATE_RESPONSE_END);
17541 - /* used the write-handler to finish the request on demand */
17546 - log_error_write(srv, __FILE__, __LINE__, "sddd", "got HUP from cgi", con->fd, hctx->fd, revents);
17549 - /* rtsigs didn't liked the close */
17550 - cgi_connection_close(srv, hctx);
17552 + fdevent_event_del(srv->ev, sess->sock);
17554 + /* someone has to close this socket now :) */
17555 + http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
17556 + joblist_append(srv, sess->remote_con);
17557 } else if (revents & FDEVENT_ERR) {
17558 con->file_finished = 1;
17561 /* kill all connections to the cgi process */
17562 - cgi_connection_close(srv, hctx);
17564 - log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR");
17566 - return HANDLER_ERROR;
17567 + fdevent_event_del(srv->ev, sess->sock);
17571 return HANDLER_FINISHED;
17575 static int cgi_env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
17579 if (!key || !val) return -1;
17582 dst = malloc(key_len + val_len + 3);
17583 memcpy(dst, key, key_len);
17584 dst[key_len] = '=';
17585 /* add the \0 from the value */
17586 memcpy(dst + key_len + 1, val, val_len + 1);
17589 if (env->size == 0) {
17591 env->ptr = malloc(env->size * sizeof(*env->ptr));
17592 @@ -678,45 +547,45 @@
17594 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
17598 env->ptr[env->used++] = dst;
17604 static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *cgi_handler) {
17609 char b2[INET6_ADDRSTRLEN + 1];
17614 int from_cgi_fds[2];
17622 if (cgi_handler->used > 1) {
17623 /* stat the exec file */
17624 if (-1 == (stat(cgi_handler->ptr, &st))) {
17625 - log_error_write(srv, __FILE__, __LINE__, "sbss",
17626 + log_error_write(srv, __FILE__, __LINE__, "sbss",
17627 "stat for cgi-handler", cgi_handler,
17628 "failed:", strerror(errno));
17634 if (pipe(to_cgi_fds)) {
17635 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
17640 if (pipe(from_cgi_fds)) {
17641 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
17647 switch (pid = fork()) {
17649 @@ -730,44 +599,40 @@
17652 server_socket *srv_sock = con->srv_socket;
17655 /* move stdout to from_cgi_fd[1] */
17656 close(STDOUT_FILENO);
17657 dup2(from_cgi_fds[1], STDOUT_FILENO);
17658 close(from_cgi_fds[1]);
17660 close(from_cgi_fds[0]);
17663 /* move the stdin to to_cgi_fd[0] */
17664 close(STDIN_FILENO);
17665 dup2(to_cgi_fds[0], STDIN_FILENO);
17666 close(to_cgi_fds[0]);
17668 close(to_cgi_fds[1]);
17671 - * this is not nice, but it works
17673 - * we feed the stderr of the CGI to our errorlog, if possible
17676 + * FIXME: add a event-handler for STDERR_FILENO and let it LOG()
17678 - if (srv->errorlog_mode == ERRORLOG_FILE) {
17679 - close(STDERR_FILENO);
17680 - dup2(srv->errorlog_fd, STDERR_FILENO);
17684 + close(STDERR_FILENO);
17686 /* create environment */
17692 cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
17694 if (!buffer_is_empty(con->server_name)) {
17695 cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
17698 - s = inet_ntop(srv_sock->addr.plain.sa_family,
17699 - srv_sock->addr.plain.sa_family == AF_INET6 ?
17700 + s = inet_ntop(srv_sock->addr.plain.sa_family,
17701 + srv_sock->addr.plain.sa_family == AF_INET6 ?
17702 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
17703 (const void *) &(srv_sock->addr.ipv4.sin_addr),
17705 @@ -779,10 +644,10 @@
17706 cgi_env_add(&env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
17708 s = get_http_version_name(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 +655,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 +676,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 +696,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 +704,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 +731,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 +761,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 +810,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 +820,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 +837,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 +861,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 +880,7 @@
17955 /* chunk_reset() or chunk_free() will cleanup for us */
17958 @@ -1020,7 +888,7 @@
17961 con->http_status = 507;
17966 con->http_status = 403;
17967 @@ -1033,7 +901,7 @@
17970 con->http_status = 507;
17975 con->http_status = 403;
17976 @@ -1056,103 +924,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 + assert(sess->sock);
18008 + sess->sock->fd = from_cgi_fds[0];
18009 + sess->sock->type = IOSOCKET_TYPE_PIPE;
18011 + if (-1 == fdevent_fcntl_set(srv->ev, sess->sock)) {
18012 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
18014 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18015 - fdevent_unregister(srv->ev, hctx->fd);
18017 - log_error_write(srv, __FILE__, __LINE__, "sd", "cgi close:", hctx->fd);
18021 - cgi_handler_ctx_free(hctx);
18023 - con->plugin_ctx[p->id] = NULL;
18026 + cgi_session_free(sess);
18032 + con->plugin_ctx[p->id] = sess;
18034 + fdevent_register(srv->ev, sess->sock, cgi_handle_fdevent, sess);
18035 + fdevent_event_add(srv->ev, sess->sock, FDEVENT_IN);
18037 + sess->state = CGI_STATE_READ_RESPONSE_HEADER;
18050 -#define PATCH(x) \
18051 - p->conf.x = s->x;
18052 static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p) {
18054 plugin_config *s = p->config_storage[0];
18059 + PATCH_OPTION(cgi);
18061 /* skip the first, the global context */
18062 for (i = 1; i < srv->config_context->used; i++) {
18063 data_config *dc = (data_config *)srv->config_context->data[i];
18064 s = p->config_storage[i];
18067 /* condition didn't match */
18068 if (!config_check_cond(srv, con, dc)) continue;
18072 for (j = 0; j < dc->value->used; j++) {
18073 data_unset *du = dc->value->data[j];
18076 if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.assign"))) {
18078 + PATCH_OPTION(cgi);
18088 URIHANDLER_FUNC(cgi_is_handled) {
18090 plugin_data *p = p_d;
18091 buffer *fn = con->physical.path;
18094 if (fn->used == 0) return HANDLER_GO_ON;
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 +1020,7 @@
18126 return HANDLER_GO_ON;
18129 @@ -1168,11 +1028,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 +1042,7 @@
18146 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
18149 return HANDLER_ERROR;
18152 @@ -1193,96 +1053,105 @@
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);
18261 con->plugin_ctx[p->id] = NULL;
18264 return HANDLER_FINISHED;
18266 - /* cgi process exited cleanly
18268 - * check if we already got the response
18271 - if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
18273 + con->file_finished = 1;
18275 if (WIFEXITED(status)) {
18278 log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
18281 con->mode = DIRECT;
18282 con->http_status = 500;
18289 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18290 - fdevent_unregister(srv->ev, hctx->fd);
18292 - if (close(hctx->fd)) {
18293 - log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
18296 - cgi_handler_ctx_free(hctx);
18301 + fdevent_event_del(srv->ev, sess->sock);
18302 + fdevent_unregister(srv->ev, sess->sock);
18304 + cgi_session_free(sess);
18307 con->plugin_ctx[p->id] = NULL;
18308 return HANDLER_FINISHED;
18310 @@ -1306,8 +1175,8 @@
18311 p->init = mod_cgi_init;
18312 p->cleanup = mod_cgi_free;
18313 p->set_defaults = mod_fastcgi_set_defaults;
18321 --- ../lighttpd-1.4.11/src/mod_cml.c 2006-01-30 13:51:48.000000000 +0200
18322 +++ lighttpd-1.4.12/src/mod_cml.c 2006-07-16 00:26:03.000000000 +0300
18324 #include <stdlib.h>
18325 #include <string.h>
18327 -#include <unistd.h>
18330 #include "buffer.h"
18331 @@ -20,50 +19,50 @@
18332 /* init the plugin data */
18333 INIT_FUNC(mod_cml_init) {
18337 p = calloc(1, sizeof(*p));
18340 p->basedir = buffer_init();
18341 p->baseurl = buffer_init();
18342 p->trigger_handler = buffer_init();
18348 /* detroy the plugin data */
18349 FREE_FUNC(mod_cml_free) {
18350 plugin_data *p = p_d;
18355 if (!p) return HANDLER_GO_ON;
18358 if (p->config_storage) {
18360 for (i = 0; i < srv->config_context->used; i++) {
18361 plugin_config *s = p->config_storage[i];
18364 buffer_free(s->ext);
18367 buffer_free(s->mc_namespace);
18368 buffer_free(s->power_magnet);
18369 array_free(s->mc_hosts);
18372 #if defined(HAVE_MEMCACHE_H)
18373 if (s->mc) mc_free(s->mc);
18379 free(p->config_storage);
18383 buffer_free(p->trigger_handler);
18384 buffer_free(p->basedir);
18385 buffer_free(p->baseurl);
18391 return HANDLER_GO_ON;
18394 @@ -72,22 +71,22 @@
18395 SETDEFAULTS_FUNC(mod_cml_set_defaults) {
18396 plugin_data *p = p_d;
18399 - config_values_t cv[] = {
18401 + config_values_t cv[] = {
18402 { "cml.extension", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
18403 { "cml.memcache-hosts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
18404 { "cml.memcache-namespace", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
18405 { "cml.power-magnet", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
18406 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
18410 if (!p) return HANDLER_ERROR;
18413 p->config_storage = malloc(srv->config_context->used * sizeof(specific_config *));
18416 for (i = 0; i < srv->config_context->used; i++) {
18420 s = malloc(sizeof(plugin_config));
18421 s->ext = buffer_init();
18422 s->mc_hosts = array_init();
18423 @@ -96,87 +95,84 @@
18424 #if defined(HAVE_MEMCACHE_H)
18429 cv[0].destination = s->ext;
18430 cv[1].destination = s->mc_hosts;
18431 cv[2].destination = s->mc_namespace;
18432 cv[3].destination = s->power_magnet;
18435 p->config_storage[i] = s;
18438 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
18439 return HANDLER_ERROR;
18443 if (s->mc_hosts->used) {
18444 #if defined(HAVE_MEMCACHE_H)
18449 for (k = 0; k < s->mc_hosts->used; k++) {
18450 data_string *ds = (data_string *)s->mc_hosts->data[k];
18453 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
18454 - log_error_write(srv, __FILE__, __LINE__, "sb",
18455 - "connection to host failed:",
18456 + log_error_write(srv, __FILE__, __LINE__, "sb",
18457 + "connection to host failed:",
18461 return HANDLER_ERROR;
18465 - log_error_write(srv, __FILE__, __LINE__, "s",
18466 + log_error_write(srv, __FILE__, __LINE__, "s",
18467 "memcache support is not compiled in but cml.memcache-hosts is set, aborting");
18468 return HANDLER_ERROR;
18474 return HANDLER_GO_ON;
18477 -#define PATCH(x) \
18478 - p->conf.x = s->x;
18479 static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p) {
18481 plugin_config *s = p->config_storage[0];
18485 + PATCH_OPTION(ext);
18486 #if defined(HAVE_MEMCACHE_H)
18488 + PATCH_OPTION(mc);
18490 - PATCH(mc_namespace);
18491 - PATCH(power_magnet);
18493 + PATCH_OPTION(mc_namespace);
18494 + PATCH_OPTION(power_magnet);
18496 /* skip the first, the global context */
18497 for (i = 1; i < srv->config_context->used; i++) {
18498 data_config *dc = (data_config *)srv->config_context->data[i];
18499 s = p->config_storage[i];
18502 /* condition didn't match */
18503 if (!config_check_cond(srv, con, dc)) continue;
18507 for (j = 0; j < dc->value->used; j++) {
18508 data_unset *du = dc->value->data[j];
18511 if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.extension"))) {
18513 + PATCH_OPTION(ext);
18514 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-hosts"))) {
18515 #if defined(HAVE_MEMCACHE_H)
18517 + PATCH_OPTION(mc);
18519 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-namespace"))) {
18520 - PATCH(mc_namespace);
18521 + PATCH_OPTION(mc_namespace);
18522 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.power-magnet"))) {
18523 - PATCH(power_magnet);
18524 + PATCH_OPTION(power_magnet);
18534 int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
18536 @@ -187,57 +183,57 @@
18538 buffer_copy_string_buffer(b, con->uri.path);
18539 for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
18543 b->used = c - b->ptr + 2;
18549 buffer_copy_string_buffer(b, con->physical.path);
18550 for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
18554 b->used = c - b->ptr + 2;
18560 /* prepare variables
18562 * - get-param-based
18566 return cache_parse_lua(srv, con, p, cml_file);
18571 URIHANDLER_FUNC(mod_cml_power_magnet) {
18572 plugin_data *p = p_d;
18575 mod_cml_patch_connection(srv, con, p);
18578 buffer_reset(p->basedir);
18579 buffer_reset(p->baseurl);
18580 buffer_reset(p->trigger_handler);
18582 if (buffer_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
18588 * cml.power-magnet = server.docroot + "/rewrite.cml"
18590 * is called on EACH request, take the original REQUEST_URI and modifies the
18591 - * request header as neccesary.
18592 + * request header as neccesary.
18595 * if file_exists("/maintainance.html") {
18596 * output_include = ( "/maintainance.html" )
18597 - * return CACHE_HIT
18598 + * return CACHE_HIT
18601 * as we only want to rewrite HTML like requests we should cover it in a conditional
18606 switch(cache_call_lua(srv, con, p, p->conf.power_magnet)) {
18607 @@ -266,20 +262,20 @@
18609 URIHANDLER_FUNC(mod_cml_is_handled) {
18610 plugin_data *p = p_d;
18613 if (buffer_is_empty(con->physical.path)) return HANDLER_ERROR;
18616 mod_cml_patch_connection(srv, con, p);
18619 buffer_reset(p->basedir);
18620 buffer_reset(p->baseurl);
18621 buffer_reset(p->trigger_handler);
18623 if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON;
18626 if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, p->conf.ext->used - 1)) {
18627 return HANDLER_GO_ON;
18631 switch(cache_call_lua(srv, con, p, con->physical.path)) {
18633 @@ -311,15 +307,15 @@
18634 int mod_cml_plugin_init(plugin *p) {
18635 p->version = LIGHTTPD_VERSION_ID;
18636 p->name = buffer_init_string("cache");
18639 p->init = mod_cml_init;
18640 p->cleanup = mod_cml_free;
18641 p->set_defaults = mod_cml_set_defaults;
18644 p->handle_subrequest_start = mod_cml_is_handled;
18645 p->handle_physical = mod_cml_power_magnet;
18653 --- ../lighttpd-1.4.11/src/mod_cml.h 2006-01-30 13:51:35.000000000 +0200
18654 +++ lighttpd-1.4.12/src/mod_cml.h 2006-07-16 00:26:03.000000000 +0300
18655 @@ -16,10 +16,10 @@
18662 buffer *mc_namespace;
18663 -#if defined(HAVE_MEMCACHE_H)
18664 +#if defined(HAVE_MEMCACHE_H)
18665 struct memcache *mc;
18667 buffer *power_magnet;
18668 @@ -27,15 +27,15 @@
18678 buffer *trigger_handler;
18681 plugin_config **config_storage;
18683 - plugin_config conf;
18685 + plugin_config conf;
18688 int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn);
18689 --- ../lighttpd-1.4.11/src/mod_cml_funcs.c 2005-11-17 16:15:08.000000000 +0200
18690 +++ lighttpd-1.4.12/src/mod_cml_funcs.c 2006-07-16 00:26:04.000000000 +0300
18692 #include <stdlib.h>
18693 #include <string.h>
18695 -#include <unistd.h>
18696 -#include <dirent.h>
18700 #include "buffer.h"
18703 #include "plugin.h"
18704 #include "response.h"
18705 +#include "sys-files.h"
18707 #include "mod_cml.h"
18708 #include "mod_cml_funcs.h"
18718 @@ -42,29 +42,29 @@
18721 int n = lua_gettop(L);
18726 b.size = sizeof(hex);
18730 lua_pushstring(L, "md5: expected one argument");
18735 if (!lua_isstring(L, 1)) {
18736 lua_pushstring(L, "md5: argument has to be a string");
18742 MD5_Update(&Md5Ctx, (unsigned char *)lua_tostring(L, 1), lua_strlen(L, 1));
18743 MD5_Final(HA1, &Md5Ctx);
18746 buffer_copy_string_hex(&b, (char *)HA1, 16);
18749 lua_pushstring(L, b.ptr);
18755 @@ -72,37 +72,37 @@
18756 int f_file_mtime(lua_State *L) {
18758 int n = lua_gettop(L);
18762 lua_pushstring(L, "file_mtime: expected one argument");
18767 if (!lua_isstring(L, 1)) {
18768 lua_pushstring(L, "file_mtime: argument has to be a string");
18773 if (-1 == stat(lua_tostring(L, 1), &st)) {
18779 lua_pushnumber(L, st.st_mtime);
18786 int f_dir_files_iter(lua_State *L) {
18791 d = lua_touserdata(L, lua_upvalueindex(1));
18794 if (NULL == (de = readdir(d))) {
18801 lua_pushstring(L, de->d_name);
18802 @@ -113,75 +113,75 @@
18803 int f_dir_files(lua_State *L) {
18805 int n = lua_gettop(L);
18809 lua_pushstring(L, "dir_files: expected one argument");
18814 if (!lua_isstring(L, 1)) {
18815 lua_pushstring(L, "dir_files: argument has to be a string");
18819 - /* check if there is a valid DIR handle on the stack */
18821 + /* check if there is a valid DIR handle on the stack */
18822 if (NULL == (d = opendir(lua_tostring(L, 1)))) {
18828 /* push d into registry */
18829 lua_pushlightuserdata(L, d);
18830 lua_pushcclosure(L, f_dir_files_iter, 1);
18837 int f_file_isreg(lua_State *L) {
18839 int n = lua_gettop(L);
18843 lua_pushstring(L, "file_isreg: expected one argument");
18848 if (!lua_isstring(L, 1)) {
18849 lua_pushstring(L, "file_isreg: argument has to be a string");
18854 if (-1 == stat(lua_tostring(L, 1), &st)) {
18860 lua_pushnumber(L, S_ISREG(st.st_mode));
18866 int f_file_isdir(lua_State *L) {
18868 int n = lua_gettop(L);
18872 lua_pushstring(L, "file_isreg: expected one argument");
18877 if (!lua_isstring(L, 1)) {
18878 lua_pushstring(L, "file_isreg: argument has to be a string");
18883 if (-1 == stat(lua_tostring(L, 1), &st)) {
18889 lua_pushnumber(L, S_ISDIR(st.st_mode));
18895 @@ -192,33 +192,33 @@
18897 int n = lua_gettop(L);
18898 struct memcache *mc;
18901 if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18902 lua_pushstring(L, "where is my userdata ?");
18907 mc = lua_touserdata(L, lua_upvalueindex(1));
18911 lua_pushstring(L, "expected one argument");
18916 if (!lua_isstring(L, 1)) {
18917 lua_pushstring(L, "argument has to be a string");
18921 - if (NULL == (r = mc_aget(mc,
18923 + if (NULL == (r = mc_aget(mc,
18924 lua_tostring(L, 1), lua_strlen(L, 1)))) {
18927 lua_pushboolean(L, 0);
18935 lua_pushboolean(L, 1);
18938 @@ -226,74 +226,74 @@
18939 int f_memcache_get_string(lua_State *L) {
18941 int n = lua_gettop(L);
18944 struct memcache *mc;
18947 if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18948 lua_pushstring(L, "where is my userdata ?");
18953 mc = lua_touserdata(L, lua_upvalueindex(1));
18959 lua_pushstring(L, "expected one argument");
18964 if (!lua_isstring(L, 1)) {
18965 lua_pushstring(L, "argument has to be a string");
18969 - if (NULL == (r = mc_aget(mc,
18971 + if (NULL == (r = mc_aget(mc,
18972 lua_tostring(L, 1), lua_strlen(L, 1)))) {
18978 lua_pushstring(L, r);
18987 int f_memcache_get_long(lua_State *L) {
18989 int n = lua_gettop(L);
18992 struct memcache *mc;
18995 if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18996 lua_pushstring(L, "where is my userdata ?");
19001 mc = lua_touserdata(L, lua_upvalueindex(1));
19007 lua_pushstring(L, "expected one argument");
19012 if (!lua_isstring(L, 1)) {
19013 lua_pushstring(L, "argument has to be a string");
19017 - if (NULL == (r = mc_aget(mc,
19019 + if (NULL == (r = mc_aget(mc,
19020 lua_tostring(L, 1), lua_strlen(L, 1)))) {
19026 lua_pushnumber(L, strtol(r, NULL, 10));
19035 --- ../lighttpd-1.4.11/src/mod_cml_lua.c 2006-01-30 13:56:40.000000000 +0200
19036 +++ lighttpd-1.4.12/src/mod_cml_lua.c 2006-07-16 00:26:04.000000000 +0300
19049 #include <lualib.h>
19050 +#include <lauxlib.h>
19054 @@ -39,11 +40,11 @@
19056 static const char * load_file(lua_State *L, void *data, size_t *size) {
19063 if (rm->done) return 0;
19066 *size = rm->st.size;
19068 return rm->st.start;
19069 @@ -51,47 +52,47 @@
19071 static int lua_to_c_get_string(lua_State *L, const char *varname, buffer *b) {
19075 lua_pushstring(L, varname);
19078 curelem = lua_gettop(L);
19079 lua_gettable(L, LUA_GLOBALSINDEX);
19082 /* it should be a table */
19083 if (!lua_isstring(L, curelem)) {
19084 lua_settop(L, curelem - 1);
19091 buffer_copy_string(b, lua_tostring(L, curelem));
19097 assert(curelem - 1 == lua_gettop(L));
19103 static int lua_to_c_is_table(lua_State *L, const char *varname) {
19107 lua_pushstring(L, varname);
19110 curelem = lua_gettop(L);
19111 lua_gettable(L, LUA_GLOBALSINDEX);
19114 /* it should be a table */
19115 if (!lua_istable(L, curelem)) {
19116 lua_settop(L, curelem - 1);
19123 lua_settop(L, curelem - 1);
19126 assert(curelem - 1 == lua_gettop(L));
19133 lua_pushlstring(L, key, key_len);
19134 lua_pushlstring(L, val, val_len);
19135 lua_settable(L, tbl);
19141 @@ -108,21 +109,21 @@
19144 char *key = NULL, *val = NULL;
19150 /* we need the \0 */
19151 for (i = 0; i < qrystr->used; i++) {
19152 switch(qrystr->ptr[i]) {
19155 val = qrystr->ptr + i + 1;
19158 qrystr->ptr[i] = '\0';
19167 case '\0': /* fin symbol */
19168 @@ -131,19 +132,19 @@
19170 /* terminate the value */
19171 qrystr->ptr[i] = '\0';
19173 - c_to_lua_push(L, tbl,
19175 + c_to_lua_push(L, tbl,
19181 key = qrystr->ptr + i + 1;
19192 @@ -151,21 +152,21 @@
19198 if (NULL != (d = array_get_element(con->request.headers, "Cookie"))) {
19199 data_string *ds = (data_string *)d;
19200 size_t key = 0, value = 0;
19201 size_t is_key = 1, is_sid = 0;
19206 if (!DATA_IS_STRING(d)) return -1;
19207 if (ds->value->used == 0) return -1;
19210 if (ds->value->ptr[0] == '\0' ||
19211 ds->value->ptr[0] == '=' ||
19212 ds->value->ptr[0] == ';') return -1;
19215 buffer_reset(p->session_id);
19216 for (i = 0; i < ds->value->used; i++) {
19217 switch(ds->value->ptr[i]) {
19218 @@ -176,16 +177,16 @@
19231 buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value);
19238 @@ -204,48 +205,43 @@
19248 int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
19253 buffer *b = buffer_init();
19254 int header_tbl = 0;
19258 stream_open(&rm.st, fn);
19261 /* push the lua file to the interpreter and see what happends */
19265 - luaopen_table(L);
19266 - luaopen_string(L);
19270 + L = luaL_newstate();
19271 + luaL_openlibs(L);
19273 /* register functions */
19274 lua_register(L, "md5", f_crypto_md5);
19275 lua_register(L, "file_mtime", f_file_mtime);
19276 lua_register(L, "file_isreg", f_file_isreg);
19277 lua_register(L, "file_isdir", f_file_isreg);
19278 lua_register(L, "dir_files", f_dir_files);
19281 #ifdef HAVE_MEMCACHE_H
19282 lua_pushliteral(L, "memcache_get_long");
19283 lua_pushlightuserdata(L, p->conf.mc);
19284 lua_pushcclosure(L, f_memcache_get_long, 1);
19285 lua_settable(L, LUA_GLOBALSINDEX);
19288 lua_pushliteral(L, "memcache_get_string");
19289 lua_pushlightuserdata(L, p->conf.mc);
19290 lua_pushcclosure(L, f_memcache_get_string, 1);
19291 lua_settable(L, LUA_GLOBALSINDEX);
19294 lua_pushliteral(L, "memcache_exists");
19295 lua_pushlightuserdata(L, p->conf.mc);
19296 lua_pushcclosure(L, f_memcache_exists, 1);
19297 @@ -255,11 +251,11 @@
19298 lua_pushliteral(L, "request");
19300 lua_settable(L, LUA_GLOBALSINDEX);
19303 lua_pushliteral(L, "request");
19304 header_tbl = lua_gettop(L);
19305 lua_gettable(L, LUA_GLOBALSINDEX);
19308 c_to_lua_push(L, header_tbl, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
19309 c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
19310 c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
19311 @@ -267,84 +263,84 @@
19312 if (!buffer_is_empty(con->request.pathinfo)) {
19313 c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
19317 c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir));
19318 c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl));
19321 /* register GET parameter */
19322 lua_pushliteral(L, "get");
19324 lua_settable(L, LUA_GLOBALSINDEX);
19327 lua_pushliteral(L, "get");
19328 header_tbl = lua_gettop(L);
19329 lua_gettable(L, LUA_GLOBALSINDEX);
19332 buffer_copy_string_buffer(b, con->uri.query);
19333 cache_export_get_params(L, header_tbl, b);
19336 - /* 2 default constants */
19337 + /* 2 default constants */
19338 lua_pushliteral(L, "CACHE_HIT");
19339 lua_pushboolean(L, 0);
19340 lua_settable(L, LUA_GLOBALSINDEX);
19343 lua_pushliteral(L, "CACHE_MISS");
19344 lua_pushboolean(L, 1);
19345 lua_settable(L, LUA_GLOBALSINDEX);
19348 /* load lua program */
19349 if (lua_load(L, load_file, &rm, fn->ptr) || lua_pcall(L,0,1,0)) {
19350 log_error_write(srv, __FILE__, __LINE__, "s",
19351 lua_tostring(L,-1));
19358 /* get return value */
19359 ret = (int)lua_tonumber(L, -1);
19362 - /* fetch the data from lua */
19364 + /* fetch the data from lua */
19365 lua_to_c_get_string(L, "trigger_handler", p->trigger_handler);
19368 if (0 == lua_to_c_get_string(L, "output_contenttype", b)) {
19369 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b));
19374 /* up to now it is a cache-hit, check if all files exist */
19381 if (!lua_to_c_is_table(L, "output_include")) {
19382 log_error_write(srv, __FILE__, __LINE__, "s",
19383 "output_include is missing or not a table");
19391 lua_pushstring(L, "output_include");
19394 curelem = lua_gettop(L);
19395 lua_gettable(L, LUA_GLOBALSINDEX);
19397 /* HOW-TO build a etag ?
19398 - * as we don't just have one file we have to take the stat()
19399 + * as we don't just have one file we have to take the stat()
19400 * from all base files, merge them and build the etag from
19404 * The mtime of the content is the mtime of the freshest base file
19410 lua_pushnil(L); /* first key */
19411 while (lua_next(L, curelem) != 0) {
19412 stat_cache_entry *sce = NULL;
19413 /* key' is at index -2 and value' at index -1 */
19416 if (lua_isstring(L, -1)) {
19417 const char *s = lua_tostring(L, -1);
19419 @@ -364,18 +360,18 @@
19420 /* a file is missing, call the handler to generate it */
19421 if (!buffer_is_empty(p->trigger_handler)) {
19422 ret = 1; /* cache-miss */
19425 log_error_write(srv, __FILE__, __LINE__, "s",
19426 "a file is missing, calling handler");
19431 /* handler not set -> 500 */
19435 log_error_write(srv, __FILE__, __LINE__, "s",
19436 "a file missing and no handler set");
19442 @@ -393,12 +389,12 @@
19448 lua_pop(L, 1); /* removes value'; keeps key' for next iteration */
19452 lua_settop(L, curelem - 1);
19457 char timebuf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
19458 @@ -410,9 +406,9 @@
19460 /* no Last-Modified specified */
19461 if ((mtime) && (NULL == ds)) {
19464 strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime));
19467 response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), timebuf, sizeof(timebuf) - 1);
19470 @@ -428,9 +424,9 @@
19476 if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, &tbuf)) {
19477 - /* ok, the client already has our content,
19478 + /* ok, the client already has our content,
19479 * no need to send it again */
19481 chunkqueue_reset(con->write_queue);
19482 @@ -440,24 +436,24 @@
19483 chunkqueue_reset(con->write_queue);
19488 if (ret == 1 && !buffer_is_empty(p->trigger_handler)) {
19490 buffer_copy_string_buffer(con->uri.path, p->baseurl);
19491 buffer_append_string_buffer(con->uri.path, p->trigger_handler);
19494 buffer_copy_string_buffer(con->physical.path, p->basedir);
19495 buffer_append_string_buffer(con->physical.path, p->trigger_handler);
19498 chunkqueue_reset(con->write_queue);
19506 stream_close(&rm.st);
19510 return ret /* cache-error */;
19513 --- ../lighttpd-1.4.11/src/mod_compress.c 2005-11-18 13:49:14.000000000 +0200
19514 +++ lighttpd-1.4.12/src/mod_compress.c 2006-07-16 00:26:04.000000000 +0300
19516 #include <sys/stat.h>
19519 -#include <unistd.h>
19521 #include <stdlib.h>
19522 #include <string.h>
19524 #include "buffer.h"
19525 #include "response.h"
19526 #include "stat_cache.h"
19527 +#include "http_chunk.h"
19529 #include "plugin.h"
19534 #include "sys-mmap.h"
19535 +#include "sys-files.h"
19537 /* request: accept-encoding */
19538 #define HTTP_ACCEPT_ENCODING_IDENTITY BV(0)
19539 @@ -55,97 +56,127 @@
19545 plugin_config **config_storage;
19546 - plugin_config conf;
19547 + plugin_config conf;
19550 INIT_FUNC(mod_compress_init) {
19554 p = calloc(1, sizeof(*p));
19557 p->ofn = buffer_init();
19558 p->b = buffer_init();
19564 FREE_FUNC(mod_compress_free) {
19565 plugin_data *p = p_d;
19570 if (!p) return HANDLER_GO_ON;
19573 buffer_free(p->ofn);
19577 if (p->config_storage) {
19579 for (i = 0; i < srv->config_context->used; i++) {
19580 plugin_config *s = p->config_storage[i];
19585 array_free(s->compress);
19586 buffer_free(s->compress_cache_dir);
19591 free(p->config_storage);
19600 return HANDLER_GO_ON;
19603 +void mkdir_recursive(const char *dir) {
19605 + char dir_copy[256];
19606 + char *p = dir_copy;
19608 + if (!dir || !dir[0])
19611 + strncpy(dir_copy, dir, sizeof(dir_copy) / sizeof(dir_copy[0]));
19613 + while ((p = strchr(p + 1, '/')) != NULL) {
19616 + if ((mkdir(dir_copy, 0700) != 0) && (errno != EEXIST))
19622 + mkdir(dir, 0700);
19625 SETDEFAULTS_FUNC(mod_compress_setdefaults) {
19626 plugin_data *p = p_d;
19629 - config_values_t cv[] = {
19631 + config_values_t cv[] = {
19632 { "compress.cache-dir", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
19633 { "compress.filetype", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
19634 { "compress.max-filesize", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
19635 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
19639 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
19642 for (i = 0; i < srv->config_context->used; i++) {
19646 s = calloc(1, sizeof(plugin_config));
19647 s->compress_cache_dir = buffer_init();
19648 s->compress = array_init();
19649 s->compress_max_filesize = 0;
19652 cv[0].destination = s->compress_cache_dir;
19653 cv[1].destination = s->compress;
19654 cv[2].destination = &(s->compress_max_filesize);
19657 p->config_storage[i] = s;
19660 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
19661 return HANDLER_ERROR;
19665 if (!buffer_is_empty(s->compress_cache_dir)) {
19667 if (0 != stat(s->compress_cache_dir->ptr, &st)) {
19668 - log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir",
19670 + log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, attempting to create",
19671 s->compress_cache_dir, strerror(errno));
19673 - return HANDLER_ERROR;
19674 + mkdir_recursive(s->compress_cache_dir->ptr);
19676 + if (0 != stat(s->compress_cache_dir->ptr, &st)) {
19678 + log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, create failed",
19679 + s->compress_cache_dir, strerror(errno));
19681 + return HANDLER_ERROR;
19688 return HANDLER_GO_ON;
19694 @@ -153,32 +184,32 @@
19707 - if (Z_OK != deflateInit2(&z,
19709 + if (Z_OK != deflateInit2(&z,
19710 Z_DEFAULT_COMPRESSION,
19713 -MAX_WBITS, /* supress zlib-header */
19715 Z_DEFAULT_STRATEGY)) {
19720 z.next_in = (unsigned char *)start;
19721 z.avail_in = st_size;
19727 buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12 + 18);
19730 /* write gzip header */
19733 c = (unsigned char *)p->b->ptr;
19736 @@ -190,24 +221,24 @@
19737 c[7] = (mtime >> 24) & 0xff;
19738 c[8] = 0x00; /* extra flags */
19739 c[9] = 0x03; /* UNIX */
19743 z.next_out = (unsigned char *)p->b->ptr + p->b->used;
19744 z.avail_out = p->b->size - p->b->used - 8;
19748 if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
19755 p->b->used += z.total_out;
19758 crc = generate_crc32c(start, st_size);
19761 c = (unsigned char *)p->b->ptr + p->b->used;
19764 c[0] = (crc >> 0) & 0xff;
19765 c[1] = (crc >> 8) & 0xff;
19766 c[2] = (crc >> 16) & 0xff;
19767 @@ -221,51 +252,51 @@
19768 if (Z_OK != deflateEnd(&z)) {
19776 static int deflate_file_to_buffer_deflate(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
19787 - if (Z_OK != deflateInit2(&z,
19789 + if (Z_OK != deflateInit2(&z,
19790 Z_DEFAULT_COMPRESSION,
19793 -MAX_WBITS, /* supress zlib-header */
19795 Z_DEFAULT_STRATEGY)) {
19801 z.avail_in = st_size;
19805 buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12);
19808 z.next_out = (unsigned char *)p->b->ptr;
19809 z.avail_out = p->b->size;
19813 if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
19820 p->b->used += z.total_out;
19823 if (Z_OK != deflateEnd(&z)) {
19831 @@ -274,48 +305,48 @@
19833 static int deflate_file_to_buffer_bzip2(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
19844 - if (BZ_OK != BZ2_bzCompressInit(&bz,
19846 + if (BZ_OK != BZ2_bzCompressInit(&bz,
19847 9, /* blocksize = 900k */
19849 0)) { /* workFactor: default */
19854 bz.next_in = (char *)start;
19855 bz.avail_in = st_size;
19856 bz.total_in_lo32 = 0;
19857 bz.total_in_hi32 = 0;
19860 buffer_prepare_copy(p->b, (bz.avail_in * 1.1) + 12);
19863 bz.next_out = p->b->ptr;
19864 bz.avail_out = p->b->size;
19865 bz.total_out_lo32 = 0;
19866 bz.total_out_hi32 = 0;
19869 if (BZ_STREAM_END != BZ2_bzCompress(&bz, BZ_FINISH)) {
19870 BZ2_bzCompressEnd(&bz);
19875 /* file is too large for now */
19876 if (bz.total_out_hi32) return -1;
19880 p->b->used = bz.total_out_lo32;
19883 if (BZ_OK != BZ2_bzCompressEnd(&bz)) {
19891 @@ -326,47 +357,50 @@
19893 const char *filename = fn->ptr;
19896 + stat_cache_entry *compressed_sce = NULL;
19898 + if (buffer_is_empty(p->conf.compress_cache_dir)) return -1;
19901 if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
19903 - /* don't mmap files > 128Mb
19906 + /* don't mmap files > 128Mb
19908 * we could use a sliding window, but currently there is no need for it
19912 if (sce->st.st_size > 128 * 1024 * 1024) return -1;
19915 buffer_reset(p->ofn);
19916 buffer_copy_string_buffer(p->ofn, p->conf.compress_cache_dir);
19917 - BUFFER_APPEND_SLASH(p->ofn);
19919 + PATHNAME_APPEND_SLASH(p->ofn);
19921 if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) {
19922 size_t offset = p->ofn->used - 1;
19923 char *dir, *nextdir;
19926 buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1);
19929 buffer_copy_string_buffer(p->b, p->ofn);
19933 for (dir = p->b->ptr + offset; NULL != (nextdir = strchr(dir, '/')); dir = nextdir + 1) {
19937 if (-1 == mkdir(p->b->ptr, 0700)) {
19938 if (errno != EEXIST) {
19939 log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cache-directory", p->b, "failed", strerror(errno));
19950 buffer_append_string_buffer(p->ofn, con->uri.path);
19955 case HTTP_ACCEPT_ENCODING_GZIP:
19956 buffer_append_string(p->ofn, "-gzip-");
19957 @@ -381,55 +415,64 @@
19958 log_error_write(srv, __FILE__, __LINE__, "sd", "unknown compression type", type);
19963 buffer_append_string_buffer(p->ofn, sce->etag);
19967 + if (HANDLER_ERROR != stat_cache_get_entry(srv, con, p->ofn, &compressed_sce)) {
19968 + /* file exists */
19970 + http_chunk_append_file(srv, con, p->ofn, 0, compressed_sce->st.st_size);
19971 + con->file_finished = 1;
19976 if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600))) {
19977 if (errno == EEXIST) {
19978 /* cache-entry exists */
19980 - log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache hit");
19982 - buffer_copy_string_buffer(con->physical.path, p->ofn);
19988 - log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cachefile", p->ofn, "failed", strerror(errno));
19991 + log_error_write(srv, __FILE__, __LINE__, "sbss",
19992 + "creating cachefile", p->ofn,
19993 + "failed", strerror(errno));
19998 - log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache miss");
20001 if (-1 == (ifd = open(filename, O_RDONLY | O_BINARY))) {
20002 - log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
20004 + log_error_write(srv, __FILE__, __LINE__, "sbss",
20005 + "opening plain-file", fn,
20006 + "failed", strerror(errno));
20017 if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
20018 - log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
20020 + log_error_write(srv, __FILE__, __LINE__, "sbss",
20022 + "failed", strerror(errno));
20032 - case HTTP_ACCEPT_ENCODING_GZIP:
20033 + case HTTP_ACCEPT_ENCODING_GZIP:
20034 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
20036 - case HTTP_ACCEPT_ENCODING_DEFLATE:
20037 + case HTTP_ACCEPT_ENCODING_DEFLATE:
20038 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
20042 - case HTTP_ACCEPT_ENCODING_BZIP2:
20043 + case HTTP_ACCEPT_ENCODING_BZIP2:
20044 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
20047 @@ -437,26 +480,27 @@
20053 if (-1 == (r = write(ofd, p->b->ptr, p->b->used))) {
20054 - munmap(start, sce->st.st_size);
20055 + munmap(start, sce->st.st_size);
20062 if ((size_t)r != p->b->used) {
20068 munmap(start, sce->st.st_size);
20073 if (ret != 0) return -1;
20075 - buffer_copy_string_buffer(con->physical.path, p->ofn);
20078 + http_chunk_append_file(srv, con, p->ofn, 0, r);
20079 + con->file_finished = 1;
20084 @@ -465,43 +509,44 @@
20091 if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
20094 /* don't mmap files > 128M
20097 * we could use a sliding window, but currently there is no need for it
20101 if (sce->st.st_size > 128 * 1024 * 1024) return -1;
20105 if (-1 == (ifd = open(fn->ptr, O_RDONLY | O_BINARY))) {
20106 log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
20113 - if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
20115 + start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0);
20119 + if (MAP_FAILED == start) {
20120 log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
20130 - case HTTP_ACCEPT_ENCODING_GZIP:
20131 + case HTTP_ACCEPT_ENCODING_GZIP:
20132 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
20134 - case HTTP_ACCEPT_ENCODING_DEFLATE:
20135 + case HTTP_ACCEPT_ENCODING_DEFLATE:
20136 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
20140 - case HTTP_ACCEPT_ENCODING_BZIP2:
20141 + case HTTP_ACCEPT_ENCODING_BZIP2:
20142 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
20145 @@ -509,69 +554,64 @@
20151 munmap(start, sce->st.st_size);
20155 if (ret != 0) return -1;
20158 chunkqueue_reset(con->write_queue);
20159 b = chunkqueue_get_append_buffer(con->write_queue);
20160 buffer_copy_memory(b, p->b->ptr, p->b->used + 1);
20163 buffer_reset(con->physical.path);
20166 con->file_finished = 1;
20167 con->file_started = 1;
20174 -#define PATCH(x) \
20175 - p->conf.x = s->x;
20176 static int mod_compress_patch_connection(server *srv, connection *con, plugin_data *p) {
20178 plugin_config *s = p->config_storage[0];
20180 - PATCH(compress_cache_dir);
20182 - PATCH(compress_max_filesize);
20184 + PATCH_OPTION(compress_cache_dir);
20185 + PATCH_OPTION(compress);
20186 + PATCH_OPTION(compress_max_filesize);
20188 /* skip the first, the global context */
20189 for (i = 1; i < srv->config_context->used; i++) {
20190 data_config *dc = (data_config *)srv->config_context->data[i];
20191 s = p->config_storage[i];
20194 /* condition didn't match */
20195 if (!config_check_cond(srv, con, dc)) continue;
20199 for (j = 0; j < dc->value->used; j++) {
20200 data_unset *du = dc->value->data[j];
20203 if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.cache-dir"))) {
20204 - PATCH(compress_cache_dir);
20205 + PATCH_OPTION(compress_cache_dir);
20206 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.filetype"))) {
20208 + PATCH_OPTION(compress);
20209 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.max-filesize"))) {
20210 - PATCH(compress_max_filesize);
20211 + PATCH_OPTION(compress_max_filesize);
20221 PHYSICALPATH_FUNC(mod_compress_physical) {
20222 plugin_data *p = p_d;
20225 stat_cache_entry *sce = NULL;
20228 /* only GET and POST can get compressed */
20229 - if (con->request.http_method != HTTP_METHOD_GET &&
20230 + if (con->request.http_method != HTTP_METHOD_GET &&
20231 con->request.http_method != HTTP_METHOD_POST) {
20232 return HANDLER_GO_ON;
20234 @@ -579,46 +619,49 @@
20235 if (buffer_is_empty(con->physical.path)) {
20236 return HANDLER_GO_ON;
20240 mod_compress_patch_connection(srv, con, p);
20243 max_fsize = p->conf.compress_max_filesize;
20245 stat_cache_get_entry(srv, con, con->physical.path, &sce);
20247 /* don't compress files that are too large as we need to much time to handle them */
20248 if (max_fsize && (sce->st.st_size >> 10) > max_fsize) return HANDLER_GO_ON;
20251 + /* compressing the file might lead to larger files instead */
20252 + if (sce->st.st_size < 128) return HANDLER_GO_ON;
20254 /* check if mimetype is in compress-config */
20255 for (m = 0; m < p->conf.compress->used; m++) {
20256 data_string *compress_ds = (data_string *)p->conf.compress->data[m];
20259 if (!compress_ds) {
20260 log_error_write(srv, __FILE__, __LINE__, "sbb", "evil", con->physical.path, con->uri.path);
20263 return HANDLER_GO_ON;
20267 if (buffer_is_equal(compress_ds->value, sce->content_type)) {
20268 /* mimetype found */
20272 /* the response might change according to Accept-Encoding */
20273 response_header_insert(srv, con, CONST_STR_LEN("Vary"), CONST_STR_LEN("Accept-Encoding"));
20276 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Encoding"))) {
20277 int accept_encoding = 0;
20278 char *value = ds->value->ptr;
20279 int srv_encodings = 0;
20280 int matched_encodings = 0;
20283 /* get client side support encodings */
20284 if (NULL != strstr(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
20285 if (NULL != strstr(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
20286 if (NULL != strstr(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS;
20287 if (NULL != strstr(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
20288 if (NULL != strstr(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY;
20291 /* get server side supported ones */
20293 srv_encodings |= HTTP_ACCEPT_ENCODING_BZIP2;
20294 @@ -627,18 +670,31 @@
20295 srv_encodings |= HTTP_ACCEPT_ENCODING_GZIP;
20296 srv_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
20300 /* find matching entries */
20301 matched_encodings = accept_encoding & srv_encodings;
20304 if (matched_encodings) {
20305 const char *dflt_gzip = "gzip";
20306 const char *dflt_deflate = "deflate";
20307 const char *dflt_bzip2 = "bzip2";
20310 const char *compression_name = NULL;
20311 int compression_type = 0;
20315 + mtime = strftime_cache_get(srv, sce->st.st_mtime);
20316 + etag_mutate(con->physical.etag, sce->etag);
20318 + response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20319 + response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20321 + /* perhaps we don't even have to compress the file as the browser still has the
20322 + * current version */
20323 + if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
20324 + return HANDLER_FINISHED;
20327 /* select best matching encoding */
20328 if (matched_encodings & HTTP_ACCEPT_ENCODING_BZIP2) {
20329 compression_type = HTTP_ACCEPT_ENCODING_BZIP2;
20330 @@ -650,31 +706,21 @@
20331 compression_type = HTTP_ACCEPT_ENCODING_DEFLATE;
20332 compression_name = dflt_deflate;
20336 - if (p->conf.compress_cache_dir->used) {
20337 - if (0 == deflate_file_to_file(srv, con, p,
20338 - con->physical.path, sce, compression_type)) {
20341 - response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
20343 - mtime = strftime_cache_get(srv, sce->st.st_mtime);
20344 - response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20346 - etag_mutate(con->physical.etag, sce->etag);
20347 - response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20349 - response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
20351 - return HANDLER_GO_ON;
20353 - } else if (0 == deflate_file_to_buffer(srv, con, p,
20354 - con->physical.path, sce, compression_type)) {
20356 - response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
20357 - response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
20360 + /* deflate it to file (cached) or to memory */
20361 + if (0 == deflate_file_to_file(srv, con, p,
20362 + con->physical.path, sce, compression_type) ||
20363 + 0 == deflate_file_to_buffer(srv, con, p,
20364 + con->physical.path, sce, compression_type)) {
20366 + response_header_overwrite(srv, con,
20367 + CONST_STR_LEN("Content-Encoding"),
20368 + compression_name, strlen(compression_name));
20370 + response_header_overwrite(srv, con,
20371 + CONST_STR_LEN("Content-Type"),
20372 + CONST_BUF_LEN(sce->content_type));
20374 return HANDLER_FINISHED;
20377 @@ -682,20 +728,20 @@
20383 return HANDLER_GO_ON;
20386 int mod_compress_plugin_init(plugin *p) {
20387 p->version = LIGHTTPD_VERSION_ID;
20388 p->name = buffer_init_string("compress");
20391 p->init = mod_compress_init;
20392 p->set_defaults = mod_compress_setdefaults;
20393 p->handle_subrequest_start = mod_compress_physical;
20394 p->cleanup = mod_compress_free;
20402 --- ../lighttpd-1.4.11/src/mod_dirlisting.c 2006-01-13 00:00:45.000000000 +0200
20403 +++ lighttpd-1.4.12/src/mod_dirlisting.c 2006-07-16 00:26:04.000000000 +0300
20406 #include <stdlib.h>
20407 #include <string.h>
20408 -#include <dirent.h>
20409 #include <assert.h>
20412 -#include <unistd.h>
20417 #include "response.h"
20418 #include "stat_cache.h"
20419 #include "stream.h"
20422 +#include "sys-strings.h"
20425 * this is a dirlisting for a lighttpd plugin
20426 @@ -27,10 +28,13 @@
20427 #include <sys/syslimits.h>
20430 -#ifdef HAVE_ATTR_ATTRIBUTES_H
20432 #include <attr/attributes.h>
20435 +#include "sys-files.h"
20436 +#include "sys-strings.h"
20438 /* plugin config for all request/connections */
20442 unsigned short hide_readme_file;
20443 unsigned short show_header;
20444 unsigned short hide_header_file;
20447 excludes_buffer *excludes;
20449 buffer *external_css;
20450 @@ -63,13 +67,14 @@
20457 buffer *content_charset;
20461 plugin_config **config_storage;
20463 - plugin_config conf;
20465 + plugin_config conf;
20468 excludes_buffer *excludes_buffer_init(void) {
20469 @@ -146,44 +151,46 @@
20470 /* init the plugin data */
20471 INIT_FUNC(mod_dirlisting_init) {
20475 p = calloc(1, sizeof(*p));
20477 p->tmp_buf = buffer_init();
20478 p->content_charset = buffer_init();
20480 + p->path = buffer_init();
20485 /* detroy the plugin data */
20486 FREE_FUNC(mod_dirlisting_free) {
20487 plugin_data *p = p_d;
20492 if (!p) return HANDLER_GO_ON;
20495 if (p->config_storage) {
20497 for (i = 0; i < srv->config_context->used; i++) {
20498 plugin_config *s = p->config_storage[i];
20504 excludes_buffer_free(s->excludes);
20505 buffer_free(s->external_css);
20506 buffer_free(s->encoding);
20511 free(p->config_storage);
20515 buffer_free(p->tmp_buf);
20516 + buffer_free(p->path);
20517 buffer_free(p->content_charset);
20523 return HANDLER_GO_ON;
20526 @@ -215,10 +222,10 @@
20527 if (0 != excludes_buffer_append(s->excludes,
20528 ((data_string *)(da->value->data[j]))->value)) {
20530 - log_error_write(srv, __FILE__, __LINE__, "sb",
20531 + log_error_write(srv, __FILE__, __LINE__, "sb",
20532 "pcre-compile failed for", ((data_string *)(da->value->data[j]))->value);
20534 - log_error_write(srv, __FILE__, __LINE__, "s",
20535 + log_error_write(srv, __FILE__, __LINE__, "s",
20536 "pcre support is missing, please install libpcre and the headers");
20539 @@ -233,8 +240,8 @@
20540 SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
20541 plugin_data *p = p_d;
20544 - config_values_t cv[] = {
20546 + config_values_t cv[] = {
20547 { "dir-listing.exclude", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
20548 { "dir-listing.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
20549 { "dir-listing.hide-dotfiles", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
20550 @@ -245,18 +252,18 @@
20551 { "dir-listing.show-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
20552 { "dir-listing.hide-header-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
20553 { "server.dir-listing", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
20556 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
20560 if (!p) return HANDLER_ERROR;
20563 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
20566 for (i = 0; i < srv->config_context->used; i++) {
20571 s = calloc(1, sizeof(plugin_config));
20572 s->excludes = excludes_buffer_init();
20573 s->dir_listing = 0;
20574 @@ -267,7 +274,7 @@
20575 s->show_header = 0;
20576 s->hide_header_file = 0;
20577 s->encoding = buffer_init();
20580 cv[0].destination = s->excludes;
20581 cv[1].destination = &(s->dir_listing);
20582 cv[2].destination = &(s->hide_dot_files);
20583 @@ -292,60 +299,57 @@
20584 return HANDLER_GO_ON;
20587 -#define PATCH(x) \
20588 - p->conf.x = s->x;
20589 static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_data *p) {
20591 plugin_config *s = p->config_storage[0];
20593 - PATCH(dir_listing);
20594 - PATCH(external_css);
20595 - PATCH(hide_dot_files);
20597 - PATCH(show_readme);
20598 - PATCH(hide_readme_file);
20599 - PATCH(show_header);
20600 - PATCH(hide_header_file);
20603 + PATCH_OPTION(dir_listing);
20604 + PATCH_OPTION(external_css);
20605 + PATCH_OPTION(hide_dot_files);
20606 + PATCH_OPTION(encoding);
20607 + PATCH_OPTION(show_readme);
20608 + PATCH_OPTION(hide_readme_file);
20609 + PATCH_OPTION(show_header);
20610 + PATCH_OPTION(hide_header_file);
20611 + PATCH_OPTION(excludes);
20613 /* skip the first, the global context */
20614 for (i = 1; i < srv->config_context->used; i++) {
20615 data_config *dc = (data_config *)srv->config_context->data[i];
20616 s = p->config_storage[i];
20619 /* condition didn't match */
20620 if (!config_check_cond(srv, con, dc)) continue;
20624 for (j = 0; j < dc->value->used; j++) {
20625 data_unset *du = dc->value->data[j];
20628 if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.activate")) ||
20629 buffer_is_equal_string(du->key, CONST_STR_LEN("server.dir-listing"))) {
20630 - PATCH(dir_listing);
20631 + PATCH_OPTION(dir_listing);
20632 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-dotfiles"))) {
20633 - PATCH(hide_dot_files);
20634 + PATCH_OPTION(hide_dot_files);
20635 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.external-css"))) {
20636 - PATCH(external_css);
20637 + PATCH_OPTION(external_css);
20638 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.encoding"))) {
20640 + PATCH_OPTION(encoding);
20641 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-readme"))) {
20642 - PATCH(show_readme);
20643 + PATCH_OPTION(show_readme);
20644 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-readme-file"))) {
20645 - PATCH(hide_readme_file);
20646 + PATCH_OPTION(hide_readme_file);
20647 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-header"))) {
20648 - PATCH(show_header);
20649 + PATCH_OPTION(show_header);
20650 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-header-file"))) {
20651 - PATCH(hide_header_file);
20652 + PATCH_OPTION(hide_header_file);
20653 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.excludes"))) {
20655 + PATCH_OPTION(excludes);
20667 @@ -432,7 +436,7 @@
20669 static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) {
20673 BUFFER_APPEND_STRING_CONST(out,
20674 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
20675 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n"
20676 @@ -492,11 +496,11 @@
20677 if (p->conf.show_header) {
20679 /* if we have a HEADER file, display it in <pre class="header"></pre> */
20682 buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
20683 - BUFFER_APPEND_SLASH(p->tmp_buf);
20684 + PATHNAME_APPEND_SLASH(p->tmp_buf);
20685 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "HEADER.txt");
20688 if (-1 != stream_open(&s, p->tmp_buf)) {
20689 BUFFER_APPEND_STRING_CONST(out, "<pre class=\"header\">");
20690 buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
20691 @@ -531,21 +535,21 @@
20693 static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) {
20697 BUFFER_APPEND_STRING_CONST(out,
20704 if (p->conf.show_readme) {
20706 /* if we have a README file, display it in <pre class="readme"></pre> */
20709 buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
20710 - BUFFER_APPEND_SLASH(p->tmp_buf);
20711 + PATHNAME_APPEND_SLASH(p->tmp_buf);
20712 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "README.txt");
20715 if (-1 != stream_open(&s, p->tmp_buf)) {
20716 BUFFER_APPEND_STRING_CONST(out, "<pre class=\"readme\">");
20717 buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
20718 @@ -553,7 +557,7 @@
20724 BUFFER_APPEND_STRING_CONST(out,
20725 "<div class=\"foot\">"
20727 @@ -576,7 +580,6 @@
20729 struct dirent *dent;
20731 - char *path, *path_file;
20733 int hide_dotfiles = p->conf.hide_dot_files;
20734 dirls_list_t dirs, files, *list;
20735 @@ -586,6 +589,7 @@
20737 const char *content_type;
20743 @@ -594,10 +598,10 @@
20747 - if (dir->used == 0) return -1;
20749 - i = dir->used - 1;
20750 + /* empty pathname, never ... */
20751 + if (buffer_is_empty(dir)) return -1;
20753 + /* max-length for the opendir */
20754 #ifdef HAVE_PATHCONF
20755 if (-1 == (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) {
20757 @@ -606,22 +610,24 @@
20758 name_max = 256; /* stupid default */
20761 -#elif defined __WIN32
20762 +#elif defined _WIN32
20763 name_max = FILENAME_MAX;
20765 name_max = NAME_MAX;
20768 - path = malloc(dir->used + name_max);
20770 - strcpy(path, dir->ptr);
20771 - path_file = path + i;
20773 - if (NULL == (dp = opendir(path))) {
20774 - log_error_write(srv, __FILE__, __LINE__, "sbs",
20775 + buffer_copy_string_buffer(p->path, dir);
20776 + PATHNAME_APPEND_SLASH(p->path);
20779 + /* append *.* to the path */
20780 + buffer_append_string(path, "*.*");
20783 + if (NULL == (dp = opendir(p->path->ptr))) {
20784 + log_error_write(srv, __FILE__, __LINE__, "sbs",
20785 "opendir failed:", dir, strerror(errno));
20791 @@ -633,7 +639,7 @@
20793 files.size = DIRLIST_BLOB_SIZE;
20797 while ((dent = readdir(dp)) != NULL) {
20798 unsigned short exclude_match = 0;
20800 @@ -686,15 +692,21 @@
20803 i = strlen(dent->d_name);
20806 /* NOTE: the manual says, d_name is never more than NAME_MAX
20807 * so this should actually not be a buffer-overflow-risk
20809 if (i > (size_t)name_max) continue;
20811 - memcpy(path_file, dent->d_name, i + 1);
20812 - if (stat(path, &st) != 0)
20814 + /* build the dirname */
20815 + buffer_copy_string_buffer(p->path, dir);
20816 + PATHNAME_APPEND_SLASH(p->path);
20817 + buffer_append_string(p->path, dent->d_name);
20819 + if (stat(p->path->ptr, &st) != 0) {
20820 + fprintf(stderr, "%s.%d: %s, %s\r\n", __FILE__, __LINE__, p->path->ptr, strerror(errno));
20825 if (S_ISDIR(st.st_mode))
20826 @@ -740,7 +752,7 @@
20828 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
20832 BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
20833 buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
20834 BUFFER_APPEND_STRING_CONST(out, "/\">");
20835 @@ -757,18 +769,22 @@
20836 tmp = files.ent[i];
20838 content_type = NULL;
20842 if (con->conf.use_xattr) {
20843 - memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
20844 + /* build the dirname */
20845 + buffer_copy_string_buffer(p->path, dir);
20846 + PATHNAME_APPEND_SLASH(p->path);
20847 + buffer_append_string_len(p->path, DIRLIST_ENT_NAME(tmp), tmp->namelen);
20849 attrlen = sizeof(attrval) - 1;
20850 - if (attr_get(path, "Content-Type", attrval, &attrlen, 0) == 0) {
20851 + if (attr_get(p->path->ptr, "Content-Type", attrval, &attrlen, 0) == 0) {
20852 attrval[attrlen] = '\0';
20853 content_type = attrval;
20859 if (content_type == NULL) {
20860 content_type = "application/octet-stream";
20861 for (k = 0; k < con->conf.mimetypes->used; k++) {
20862 @@ -788,7 +804,7 @@
20868 #ifdef HAVE_LOCALTIME_R
20869 localtime_r(&(tmp->mtime), &tm);
20870 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
20871 @@ -814,7 +830,6 @@
20877 http_list_directory_footer(srv, con, p, out);
20879 @@ -837,36 +852,55 @@
20880 URIHANDLER_FUNC(mod_dirlisting_subrequest) {
20881 plugin_data *p = p_d;
20882 stat_cache_entry *sce = NULL;
20886 - if (con->physical.path->used == 0) return HANDLER_GO_ON;
20887 - if (con->uri.path->used == 0) return HANDLER_GO_ON;
20891 + if (con->uri.path->used < 2) return HANDLER_GO_ON;
20892 if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
20894 + if (con->physical.path->used == 0) return HANDLER_GO_ON;
20896 mod_dirlisting_patch_connection(srv, con, p);
20898 if (!p->conf.dir_listing) return HANDLER_GO_ON;
20901 + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
20902 + /* just a second ago the file was still there */
20903 + return HANDLER_GO_ON;
20906 + if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
20908 if (con->conf.log_request_handling) {
20909 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Dir-Listing");
20910 log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
20913 - if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
20914 - fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, con->physical.path->ptr);
20917 + /* perhaps this a cachable request
20918 + * - we use the etag of the directory
20921 + etag_mutate(con->physical.etag, sce->etag);
20922 + response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20924 + /* prepare header */
20925 + if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
20926 + mtime = strftime_cache_get(srv, sce->st.st_mtime);
20927 + response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20929 + mtime = ds->value;
20932 - if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
20935 + if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
20936 + return HANDLER_FINISHED;
20939 if (http_list_directory(srv, con, p, con->physical.path)) {
20940 /* dirlisting failed */
20941 con->http_status = 403;
20945 buffer_reset(con->physical.path);
20949 return HANDLER_FINISHED;
20951 @@ -876,13 +910,13 @@
20952 int mod_dirlisting_plugin_init(plugin *p) {
20953 p->version = LIGHTTPD_VERSION_ID;
20954 p->name = buffer_init_string("dirlisting");
20957 p->init = mod_dirlisting_init;
20958 p->handle_subrequest_start = mod_dirlisting_subrequest;
20959 p->set_defaults = mod_dirlisting_set_defaults;
20960 p->cleanup = mod_dirlisting_free;
20968 --- ../lighttpd-1.4.11/src/mod_evasive.c 2006-01-04 15:24:51.000000000 +0200
20969 +++ lighttpd-1.4.12/src/mod_evasive.c 2006-07-16 00:26:04.000000000 +0300
20970 @@ -31,100 +31,97 @@
20976 plugin_config **config_storage;
20978 - plugin_config conf;
20980 + plugin_config conf;
20983 INIT_FUNC(mod_evasive_init) {
20987 p = calloc(1, sizeof(*p));
20993 FREE_FUNC(mod_evasive_free) {
20994 plugin_data *p = p_d;
20999 if (!p) return HANDLER_GO_ON;
21002 if (p->config_storage) {
21004 for (i = 0; i < srv->config_context->used; i++) {
21005 plugin_config *s = p->config_storage[i];
21010 free(p->config_storage);
21017 return HANDLER_GO_ON;
21020 SETDEFAULTS_FUNC(mod_evasive_set_defaults) {
21021 plugin_data *p = p_d;
21024 - config_values_t cv[] = {
21026 + config_values_t cv[] = {
21027 { "evasive.max-conns-per-ip", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
21028 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21032 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21035 for (i = 0; i < srv->config_context->used; i++) {
21039 s = calloc(1, sizeof(plugin_config));
21043 cv[0].destination = &(s->max_conns);
21046 p->config_storage[i] = s;
21049 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
21050 return HANDLER_ERROR;
21055 return HANDLER_GO_ON;
21058 -#define PATCH(x) \
21059 - p->conf.x = s->x;
21060 static int mod_evasive_patch_connection(server *srv, connection *con, plugin_data *p) {
21062 plugin_config *s = p->config_storage[0];
21064 - PATCH(max_conns);
21066 + PATCH_OPTION(max_conns);
21068 /* skip the first, the global context */
21069 for (i = 1; i < srv->config_context->used; i++) {
21070 data_config *dc = (data_config *)srv->config_context->data[i];
21071 s = p->config_storage[i];
21074 /* condition didn't match */
21075 if (!config_check_cond(srv, con, dc)) continue;
21079 for (j = 0; j < dc->value->used; j++) {
21080 data_unset *du = dc->value->data[j];
21083 if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.max-conns-per-ip"))) {
21084 - PATCH(max_conns);
21085 + PATCH_OPTION(max_conns);
21095 URIHANDLER_FUNC(mod_evasive_uri_handler) {
21096 plugin_data *p = p_d;
21097 @@ -132,10 +129,10 @@
21100 if (con->uri.path->used == 0) return HANDLER_GO_ON;
21103 mod_evasive_patch_connection(srv, con, p);
21105 - /* no limit set, nothing to block */
21107 + /* no limit set, nothing to block */
21108 if (p->conf.max_conns == 0) return HANDLER_GO_ON;
21110 for (j = 0; j < srv->conns->used; j++) {
21111 @@ -147,7 +144,7 @@
21112 if (c->dst_addr.ipv4.sin_addr.s_addr == con->dst_addr.ipv4.sin_addr.s_addr &&
21113 c->state > CON_STATE_REQUEST_END) {
21117 if (conns_by_ip > p->conf.max_conns) {
21118 log_error_write(srv, __FILE__, __LINE__, "ss",
21119 inet_ntop_cache_get_ip(srv, &(con->dst_addr)),
21120 @@ -158,7 +155,7 @@
21126 return HANDLER_GO_ON;
21129 @@ -166,13 +163,13 @@
21130 int mod_evasive_plugin_init(plugin *p) {
21131 p->version = LIGHTTPD_VERSION_ID;
21132 p->name = buffer_init_string("evasive");
21135 p->init = mod_evasive_init;
21136 p->set_defaults = mod_evasive_set_defaults;
21137 p->handle_uri_clean = mod_evasive_uri_handler;
21138 p->cleanup = mod_evasive_free;
21146 --- ../lighttpd-1.4.11/src/mod_evhost.c 2005-08-17 10:42:03.000000000 +0300
21147 +++ lighttpd-1.4.12/src/mod_evhost.c 2006-07-16 00:26:03.000000000 +0300
21149 #include "response.h"
21150 #include "stat_cache.h"
21152 +#include "sys-files.h"
21155 /* unparsed pieces */
21156 buffer *path_pieces_raw;
21159 /* pieces for path creation */
21161 buffer **path_pieces;
21162 @@ -21,14 +23,14 @@
21165 plugin_config **config_storage;
21166 - plugin_config conf;
21167 + plugin_config conf;
21170 INIT_FUNC(mod_evhost_init) {
21174 p = calloc(1, sizeof(*p));
21177 p->tmp_buf = buffer_init();
21180 @@ -36,34 +38,34 @@
21182 FREE_FUNC(mod_evhost_free) {
21183 plugin_data *p = p_d;
21188 if (!p) return HANDLER_GO_ON;
21191 if (p->config_storage) {
21193 for (i = 0; i < srv->config_context->used; i++) {
21194 plugin_config *s = p->config_storage[i];
21199 if(s->path_pieces) {
21201 for (j = 0; j < s->len; j++) {
21202 buffer_free(s->path_pieces[j]);
21206 free(s->path_pieces);
21210 buffer_free(s->path_pieces_raw);
21215 free(p->config_storage);
21219 buffer_free(p->tmp_buf);
21222 @@ -73,30 +75,30 @@
21224 static void mod_evhost_parse_pattern(plugin_config *s) {
21225 char *ptr = s->path_pieces_raw->ptr,*pos;
21228 s->path_pieces = NULL;
21231 for(pos=ptr;*ptr;ptr++) {
21233 s->path_pieces = realloc(s->path_pieces,(s->len+2) * sizeof(*s->path_pieces));
21234 s->path_pieces[s->len] = buffer_init();
21235 s->path_pieces[s->len+1] = buffer_init();
21238 buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
21242 buffer_copy_string_len(s->path_pieces[s->len+1],ptr++,2);
21251 s->path_pieces = realloc(s->path_pieces,(s->len+1) * sizeof(*s->path_pieces));
21252 s->path_pieces[s->len] = buffer_init();
21255 buffer_append_memory(s->path_pieces[s->len],pos,ptr-pos);
21261 @@ -104,9 +106,9 @@
21262 SETDEFAULTS_FUNC(mod_evhost_set_defaults) {
21263 plugin_data *p = p_d;
21271 * # define a pattern for the host url finding
21273 @@ -117,39 +119,39 @@
21274 * # %4 => subdomain 2 name
21276 * evhost.path-pattern = "/home/ckruse/dev/www/%3/htdocs/"
21281 - config_values_t cv[] = {
21283 + config_values_t cv[] = {
21284 { "evhost.path-pattern", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
21285 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21289 if (!p) return HANDLER_ERROR;
21292 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21295 for (i = 0; i < srv->config_context->used; i++) {
21299 s = calloc(1, sizeof(plugin_config));
21300 s->path_pieces_raw = buffer_init();
21301 s->path_pieces = NULL;
21305 cv[0].destination = s->path_pieces_raw;
21308 p->config_storage[i] = s;
21311 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
21312 return HANDLER_ERROR;
21316 if (s->path_pieces_raw->used != 0) {
21317 mod_evhost_parse_pattern(s);
21322 return HANDLER_GO_ON;
21325 @@ -158,7 +160,7 @@
21326 * - %0 - full hostname (authority w/o port)
21328 * - %2 - domain.tld
21333 static int mod_evhost_parse_host(connection *con,array *host) {
21334 @@ -168,7 +170,7 @@
21340 /* first, find the domain + tld */
21341 for(;ptr > con->uri.authority->ptr;ptr--) {
21343 @@ -179,18 +181,18 @@
21349 ds = data_string_init();
21350 buffer_copy_string(ds->key,"%0");
21353 /* if we stopped at a dot, skip the dot */
21354 if (*ptr == '.') ptr++;
21355 buffer_copy_string_len(ds->value, ptr, colon-ptr);
21358 array_insert_unique(host,(data_unset *)ds);
21361 /* if the : is not the start of the authority, go on parsing the hostname */
21364 if (colon != con->uri.authority->ptr) {
21365 for(ptr = colon - 1, i = 1; ptr > con->uri.authority->ptr; ptr--) {
21367 @@ -200,59 +202,55 @@
21368 buffer_copy_string(ds->key,"%");
21369 buffer_append_long(ds->key, i++);
21370 buffer_copy_string_len(ds->value,ptr+1,colon-ptr-1);
21373 array_insert_unique(host,(data_unset *)ds);
21380 /* if the . is not the first charactor of the hostname */
21381 if (colon != ptr) {
21382 ds = data_string_init();
21383 buffer_copy_string(ds->key,"%");
21384 buffer_append_long(ds->key, i++);
21385 buffer_copy_string_len(ds->value,ptr,colon-ptr);
21388 array_insert_unique(host,(data_unset *)ds);
21396 -#define PATCH(x) \
21397 - p->conf.x = s->x;
21398 static int mod_evhost_patch_connection(server *srv, connection *con, plugin_data *p) {
21400 plugin_config *s = p->config_storage[0];
21402 - PATCH(path_pieces);
21406 + PATCH_OPTION(path_pieces);
21407 + PATCH_OPTION(len);
21409 /* skip the first, the global context */
21410 for (i = 1; i < srv->config_context->used; i++) {
21411 data_config *dc = (data_config *)srv->config_context->data[i];
21412 s = p->config_storage[i];
21415 /* condition didn't match */
21416 if (!config_check_cond(srv, con, dc)) continue;
21420 for (j = 0; j < dc->value->used; j++) {
21421 data_unset *du = dc->value->data[j];
21424 if (buffer_is_equal_string(du->key, CONST_STR_LEN("evhost.path-pattern"))) {
21425 - PATCH(path_pieces);
21427 + PATCH_OPTION(path_pieces);
21428 + PATCH_OPTION(len);
21439 static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d) {
21440 plugin_data *p = p_d;
21441 @@ -261,29 +259,29 @@
21442 register char *ptr;
21444 stat_cache_entry *sce = NULL;
21447 /* not authority set */
21448 if (con->uri.authority->used == 0) return HANDLER_GO_ON;
21451 mod_evhost_patch_connection(srv, con, p);
21454 /* missing even default(global) conf */
21455 if (0 == p->conf.len) {
21456 return HANDLER_GO_ON;
21459 parsed_host = array_init();
21462 mod_evhost_parse_host(con, parsed_host);
21465 /* build document-root */
21466 buffer_reset(p->tmp_buf);
21469 for (i = 0; i < p->conf.len; i++) {
21470 ptr = p->conf.path_pieces[i]->ptr;
21475 if (*(ptr+1) == '%') {
21477 BUFFER_APPEND_STRING_CONST(p->tmp_buf,"%");
21478 @@ -298,11 +296,11 @@
21479 buffer_append_string_buffer(p->tmp_buf,p->conf.path_pieces[i]);
21483 - BUFFER_APPEND_SLASH(p->tmp_buf);
21486 + PATHNAME_APPEND_SLASH(p->tmp_buf);
21488 array_free(parsed_host);
21491 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
21492 log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
21494 @@ -310,11 +308,11 @@
21495 log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", p->tmp_buf);
21501 buffer_copy_string_buffer(con->physical.doc_root, p->tmp_buf);
21505 return HANDLER_GO_ON;
21508 @@ -325,9 +323,9 @@
21509 p->set_defaults = mod_evhost_set_defaults;
21510 p->handle_docroot = mod_evhost_uri_handler;
21511 p->cleanup = mod_evhost_free;
21520 --- ../lighttpd-1.4.11/src/mod_expire.c 2005-11-03 09:52:13.000000000 +0200
21521 +++ lighttpd-1.4.12/src/mod_expire.c 2006-07-16 00:26:04.000000000 +0300
21523 #include "stat_cache.h"
21526 - * this is a expire module for a lighttpd
21528 + * this is a expire module for a lighttpd
21530 * set 'Expires:' HTTP Headers on demand
21533 @@ -27,51 +27,51 @@
21539 buffer *expire_tstmp;
21542 plugin_config **config_storage;
21544 - plugin_config conf;
21546 + plugin_config conf;
21549 /* init the plugin data */
21550 INIT_FUNC(mod_expire_init) {
21554 p = calloc(1, sizeof(*p));
21557 p->expire_tstmp = buffer_init();
21560 buffer_prepare_copy(p->expire_tstmp, 255);
21566 /* detroy the plugin data */
21567 FREE_FUNC(mod_expire_free) {
21568 plugin_data *p = p_d;
21573 if (!p) return HANDLER_GO_ON;
21576 buffer_free(p->expire_tstmp);
21579 if (p->config_storage) {
21581 for (i = 0; i < srv->config_context->used; i++) {
21582 plugin_config *s = p->config_storage[i];
21585 array_free(s->expire_url);
21590 free(p->config_storage);
21597 return HANDLER_GO_ON;
21600 @@ -79,25 +79,25 @@
21613 * '(access|modification) [plus] {<num> <type>}*'
21616 * e.g. 'access 1 years'
21620 if (expire->used == 0) {
21621 - log_error_write(srv, __FILE__, __LINE__, "s",
21622 + log_error_write(srv, __FILE__, __LINE__, "s",
21631 if (0 == strncmp(ts, "access ", 7)) {
21634 @@ -110,39 +110,39 @@
21635 "invalid <base>:", ts);
21640 if (0 == strncmp(ts, "plus ", 5)) {
21641 /* skip the optional plus */
21646 /* the rest is just <number> (years|months|days|hours|minutes|seconds) */
21652 if (NULL == (space = strchr(ts, ' '))) {
21653 - log_error_write(srv, __FILE__, __LINE__, "ss",
21654 + log_error_write(srv, __FILE__, __LINE__, "ss",
21655 "missing space after <num>:", ts);
21660 num = strtol(ts, &err, 10);
21662 - log_error_write(srv, __FILE__, __LINE__, "ss",
21663 + log_error_write(srv, __FILE__, __LINE__, "ss",
21664 "missing <type> after <num>:", ts);
21672 if (NULL != (space = strchr(ts, ' '))) {
21682 0 == strncmp(ts, "years", slen)) {
21683 num *= 60 * 60 * 24 * 30 * 12;
21684 } else if (slen == 6 &&
21685 @@ -161,13 +161,13 @@
21686 0 == strncmp(ts, "seconds", slen)) {
21689 - log_error_write(srv, __FILE__, __LINE__, "ss",
21690 + log_error_write(srv, __FILE__, __LINE__, "ss",
21691 "unknown type:", ts);
21701 if (0 == strcmp(ts, "years")) {
21702 @@ -183,19 +183,19 @@
21703 } else if (0 == strcmp(ts, "seconds")) {
21706 - log_error_write(srv, __FILE__, __LINE__, "ss",
21707 + log_error_write(srv, __FILE__, __LINE__, "ss",
21708 "unknown type:", ts);
21721 if (offset != NULL) *offset = retts;
21727 @@ -205,102 +205,99 @@
21728 SETDEFAULTS_FUNC(mod_expire_set_defaults) {
21729 plugin_data *p = p_d;
21732 - config_values_t cv[] = {
21734 + config_values_t cv[] = {
21735 { "expire.url", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
21736 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21740 if (!p) return HANDLER_ERROR;
21743 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21746 for (i = 0; i < srv->config_context->used; i++) {
21750 s = calloc(1, sizeof(plugin_config));
21751 s->expire_url = array_init();
21754 cv[0].destination = s->expire_url;
21757 p->config_storage[i] = s;
21760 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
21761 return HANDLER_ERROR;
21765 for (k = 0; k < s->expire_url->used; k++) {
21766 data_string *ds = (data_string *)s->expire_url->data[k];
21770 if (-1 == mod_expire_get_offset(srv, p, ds->value, NULL)) {
21771 - log_error_write(srv, __FILE__, __LINE__, "sb",
21772 + log_error_write(srv, __FILE__, __LINE__, "sb",
21773 "parsing expire.url failed:", ds->value);
21774 return HANDLER_ERROR;
21782 return HANDLER_GO_ON;
21785 -#define PATCH(x) \
21786 - p->conf.x = s->x;
21787 static int mod_expire_patch_connection(server *srv, connection *con, plugin_data *p) {
21789 plugin_config *s = p->config_storage[0];
21791 - PATCH(expire_url);
21794 + PATCH_OPTION(expire_url);
21796 /* skip the first, the global context */
21797 for (i = 1; i < srv->config_context->used; i++) {
21798 data_config *dc = (data_config *)srv->config_context->data[i];
21799 s = p->config_storage[i];
21802 /* condition didn't match */
21803 if (!config_check_cond(srv, con, dc)) continue;
21807 for (j = 0; j < dc->value->used; j++) {
21808 data_unset *du = dc->value->data[j];
21811 if (buffer_is_equal_string(du->key, CONST_STR_LEN("expire.url"))) {
21812 - PATCH(expire_url);
21813 + PATCH_OPTION(expire_url);
21823 URIHANDLER_FUNC(mod_expire_path_handler) {
21824 plugin_data *p = p_d;
21829 if (con->uri.path->used == 0) return HANDLER_GO_ON;
21832 mod_expire_patch_connection(srv, con, p);
21835 s_len = con->uri.path->used - 1;
21838 for (k = 0; k < p->conf.expire_url->used; k++) {
21839 data_string *ds = (data_string *)p->conf.expire_url->data[k];
21840 int ct_len = ds->key->used - 1;
21843 if (ct_len > s_len) continue;
21844 if (ds->key->used == 0) continue;
21847 if (0 == strncmp(con->uri.path->ptr, ds->key->ptr, ct_len)) {
21851 stat_cache_entry *sce = NULL;
21854 stat_cache_get_entry(srv, con, con->physical.path, &sce);
21857 switch(mod_expire_get_offset(srv, p, ds->value, &ts)) {
21860 @@ -308,38 +305,38 @@
21866 t = (ts + sce->st.st_mtime);
21869 /* -1 is handled at parse-time */
21874 - if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
21877 + if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
21878 "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(t))))) {
21879 /* could not set expire header, out of mem */
21882 return HANDLER_GO_ON;
21888 p->expire_tstmp->used = len + 1;
21893 response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_BUF_LEN(p->expire_tstmp));
21897 buffer_copy_string(p->expire_tstmp, "max-age=");
21898 buffer_append_long(p->expire_tstmp, ts);
21901 response_header_overwrite(srv, con, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(p->expire_tstmp));
21904 return HANDLER_GO_ON;
21910 return HANDLER_GO_ON;
21912 @@ -349,13 +346,13 @@
21913 int mod_expire_plugin_init(plugin *p) {
21914 p->version = LIGHTTPD_VERSION_ID;
21915 p->name = buffer_init_string("expire");
21918 p->init = mod_expire_init;
21919 p->handle_subrequest_start = mod_expire_path_handler;
21920 p->set_defaults = mod_expire_set_defaults;
21921 p->cleanup = mod_expire_free;
21929 --- ../lighttpd-1.4.11/src/mod_fastcgi.c 2006-03-09 13:18:39.000000000 +0200
21930 +++ lighttpd-1.4.12/src/mod_fastcgi.c 2006-07-18 13:03:40.000000000 +0300
21932 #include <sys/types.h>
21933 -#include <unistd.h>
21936 #include <string.h>
21938 #include "inet_ntop_cache.h"
21939 #include "stat_cache.h"
21941 -#include <fastcgi.h>
21942 +#include "fastcgi.h"
21945 #ifdef HAVE_SYS_FILIO_H
21949 #include "sys-socket.h"
21950 +#include "sys-files.h"
21951 +#include "sys-strings.h"
21952 +#include "sys-process.h"
21954 +#include "http_resp.h"
21956 #ifndef UNIX_PATH_MAX
21957 # define UNIX_PATH_MAX 108
21958 @@ -45,14 +48,13 @@
21959 #include <sys/wait.h>
21969 * - add timeout for a connect to a non-fastcgi process
21970 * (use state_timestamp + state)
21975 typedef struct fcgi_proc {
21977 unsigned port; /* config.port + pno */
21979 buffer *connection_name; /* either tcp:<host>:<port> or unix:<socket> for debuggin purposes */
21982 pid_t pid; /* PID of the spawned process (0 if not spawned locally) */
21985 @@ -70,20 +72,20 @@
21986 time_t last_used; /* see idle_timeout */
21987 size_t requests; /* see max_requests */
21988 struct fcgi_proc *prev, *next; /* see first */
21991 time_t disabled_until; /* this proc is disabled until, use something else until than */
21998 PROC_STATE_UNSET, /* init-phase */
21999 PROC_STATE_RUNNING, /* alive */
22000 - PROC_STATE_OVERLOADED, /* listen-queue is full,
22001 + PROC_STATE_OVERLOADED, /* listen-queue is full,
22002 don't send something to this proc for the next 2 seconds */
22003 PROC_STATE_DIED_WAIT_FOR_PID, /* */
22004 PROC_STATE_DIED, /* marked as dead, should be restarted */
22005 PROC_STATE_KILLED /* was killed as we don't have the load anymore */
22011 @@ -94,20 +96,20 @@
22012 * sorted by lowest load
22014 * whenever a job is done move it up in the list
22015 - * until it is sorted, move it down as soon as the
22016 + * until it is sorted, move it down as soon as the
22019 - fcgi_proc *first;
22020 - fcgi_proc *unused_procs;
22021 + fcgi_proc *first;
22022 + fcgi_proc *unused_procs;
22026 * spawn at least min_procs, at max_procs.
22028 - * as soon as the load of the first entry
22029 + * as soon as the load of the first entry
22030 * is max_load_per_proc we spawn a new one
22031 - * and add it to the first entry and give it
22032 + * and add it to the first entry and give it
22038 unsigned short min_procs;
22039 @@ -119,44 +121,44 @@
22042 * kick the process from the list if it was not
22043 - * used for idle_timeout until min_procs is
22044 + * used for idle_timeout until min_procs is
22045 * reached. this helps to get the processlist
22046 * small again we had a small peak load.
22051 unsigned short idle_timeout;
22055 * time after a disabled remote connection is tried to be re-enabled
22063 unsigned short disable_time;
22066 * same fastcgi processes get a little bit larger
22067 - * than wanted. max_requests_per_proc kills a
22068 + * than wanted. max_requests_per_proc kills a
22069 * process after a number of handled requests.
22072 size_t max_requests_per_proc;
22083 - * if host is one of the local IP adresses the
22084 + * if host is one of the local IP adresses the
22085 * whole connection is local
22087 * if tcp/ip should be used host AND port have
22088 - * to be specified
22092 + * to be specified
22096 unsigned short port;
22099 @@ -169,7 +171,7 @@
22101 buffer *unixsocket;
22103 - /* if socket is local we can start the fastcgi
22104 + /* if socket is local we can start the fastcgi
22107 * bin-path is the path to the binary
22108 @@ -177,19 +179,19 @@
22109 * check min_procs and max_procs for the number
22110 * of process to start-up
22112 - buffer *bin_path;
22114 - /* bin-path is set bin-environment is taken to
22115 + buffer *bin_path;
22117 + /* bin-path is set bin-environment is taken to
22118 * create the environement before starting the
22126 array *bin_env_copy;
22130 - * docroot-translation between URL->phys and the
22131 + * docroot-translation between URL->phys and the
22135 @@ -208,7 +210,7 @@
22136 unsigned short mode;
22139 - * check_local tell you if the phys file is stat()ed
22140 + * check_local tell you if the phys file is stat()ed
22141 * or not. FastCGI doesn't care if the service is
22142 * remote. If the web-server side doesn't contain
22143 * the fastcgi-files we should not stat() for them
22144 @@ -218,11 +220,11 @@
22147 * append PATH_INFO to SCRIPT_FILENAME
22150 * php needs this if cgi.fix_pathinfo is provied
22156 unsigned short break_scriptfilename_for_php;
22159 @@ -231,12 +233,12 @@
22162 unsigned short allow_xsendfile;
22165 ssize_t load; /* replace by host->load */
22167 size_t max_id; /* corresponds most of the time to
22171 only if a process is killed max_id waits for the process itself
22172 to die and decrements its afterwards */
22174 @@ -245,17 +247,17 @@
22177 * one extension can have multiple hosts assigned
22178 - * one host can spawn additional processes on the same
22179 + * one host can spawn additional processes on the same
22180 * socket (if we control it)
22182 * ext -> host -> procs
22185 - * if the fastcgi process is remote that whole goes down
22186 + * if the fastcgi process is remote that whole goes down
22189 * ext -> host -> procs
22193 * in case of PHP and FCGI_CHILDREN we have again a procs
22194 * but we don't control it directly.
22195 @@ -268,7 +270,7 @@
22198 fcgi_extension_host **hosts;
22204 @@ -282,10 +284,10 @@
22211 array *ext_mapping;
22217 @@ -297,7 +299,7 @@
22226 @@ -306,55 +308,54 @@
22229 buffer_uint fcgi_request_id;
22236 - buffer *parse_response;
22243 plugin_config **config_storage;
22246 plugin_config conf; /* this is only used as long as no handler_ctx is setup */
22249 /* connection specific data */
22254 - FCGI_STATE_CONNECT_DELAYED,
22255 - FCGI_STATE_PREPARE_WRITE,
22256 - FCGI_STATE_WRITE,
22259 + FCGI_STATE_CONNECT_DELAYED,
22260 + FCGI_STATE_PREPARE_WRITE,
22261 + FCGI_STATE_WRITE,
22263 } fcgi_connection_state_t;
22267 fcgi_extension_host *host;
22268 fcgi_extension *ext;
22271 fcgi_connection_state_t state;
22272 time_t state_timestamp;
22275 int reconnects; /* number of reconnect attempts */
22277 - chunkqueue *rb; /* read queue */
22279 + chunkqueue *rb; /* the raw fcgi read-queue */
22280 + chunkqueue *http_rb; /* the decoded read-queue for http-parsing */
22281 chunkqueue *wb; /* write queue */
22283 - buffer *response_header;
22287 - int fd; /* fd to the fastcgi process */
22288 - int fde_ndx; /* index into the fd-event buffer */
22294 int send_content_body;
22297 plugin_config conf;
22300 connection *remote_conn; /* dumb pointer */
22301 plugin_data *plugin_data; /* dumb pointer */
22303 @@ -380,7 +381,7 @@
22307 -/* dummies of the statistic framework functions
22308 +/* dummies of the statistic framework functions
22309 * they will be moved to a statistics.c later */
22310 int status_counter_inc(server *srv, const char *s, size_t len) {
22311 data_integer *di = status_counter_get_counter(srv, s, len);
22312 @@ -429,7 +430,7 @@
22313 CLEAN(".connected");
22320 fastcgi_status_copy_procname(b, host, NULL); \
22321 @@ -438,33 +439,30 @@
22331 static handler_ctx * handler_ctx_init() {
22332 handler_ctx * hctx;
22335 hctx = calloc(1, sizeof(*hctx));
22338 - hctx->fde_ndx = -1;
22340 - hctx->response_header = buffer_init();
22343 hctx->request_id = 0;
22344 hctx->state = FCGI_STATE_INIT;
22350 + hctx->sock = iosocket_init();
22352 hctx->reconnects = 0;
22353 hctx->send_content_body = 1;
22355 hctx->rb = chunkqueue_init();
22356 + hctx->http_rb = chunkqueue_init();
22357 hctx->wb = chunkqueue_init();
22363 @@ -473,12 +471,13 @@
22364 hctx->host->load--;
22368 - buffer_free(hctx->response_header);
22370 chunkqueue_free(hctx->rb);
22371 + chunkqueue_free(hctx->http_rb);
22372 chunkqueue_free(hctx->wb);
22374 + iosocket_free(hctx->sock);
22379 @@ -488,21 +487,21 @@
22380 f = calloc(1, sizeof(*f));
22381 f->unixsocket = buffer_init();
22382 f->connection_name = buffer_init();
22392 void fastcgi_process_free(fcgi_proc *f) {
22396 fastcgi_process_free(f->next);
22399 buffer_free(f->unixsocket);
22400 buffer_free(f->connection_name);
22406 @@ -519,13 +518,13 @@
22407 f->bin_env = array_init();
22408 f->bin_env_copy = array_init();
22409 f->strip_request_uri = buffer_init();
22415 void fastcgi_host_free(fcgi_extension_host *h) {
22419 buffer_free(h->id);
22420 buffer_free(h->host);
22421 buffer_free(h->unixsocket);
22422 @@ -534,49 +533,49 @@
22423 buffer_free(h->strip_request_uri);
22424 array_free(h->bin_env);
22425 array_free(h->bin_env_copy);
22428 fastcgi_process_free(h->first);
22429 fastcgi_process_free(h->unused_procs);
22437 fcgi_exts *fastcgi_extensions_init() {
22440 f = calloc(1, sizeof(*f));
22446 void fastcgi_extensions_free(fcgi_exts *f) {
22453 for (i = 0; i < f->used; i++) {
22454 fcgi_extension *fe;
22461 for (j = 0; j < fe->used; j++) {
22462 fcgi_extension_host *h;
22468 fastcgi_host_free(h);
22472 buffer_free(fe->key);
22486 @@ -625,24 +624,25 @@
22490 - fe->hosts[fe->used++] = fh;
22491 + fe->hosts[fe->used++] = fh;
22498 INIT_FUNC(mod_fastcgi_init) {
22502 p = calloc(1, sizeof(*p));
22505 p->fcgi_env = buffer_init();
22508 p->path = buffer_init();
22509 - p->parse_response = buffer_init();
22511 + p->resp = http_response_init();
22513 p->statuskey = buffer_init();
22519 @@ -650,81 +650,82 @@
22520 FREE_FUNC(mod_fastcgi_free) {
22521 plugin_data *p = p_d;
22522 buffer_uint *r = &(p->fcgi_request_id);
22527 if (r->ptr) free(r->ptr);
22530 buffer_free(p->fcgi_env);
22531 buffer_free(p->path);
22532 - buffer_free(p->parse_response);
22533 buffer_free(p->statuskey);
22536 + http_response_free(p->resp);
22538 if (p->config_storage) {
22540 for (i = 0; i < srv->config_context->used; i++) {
22541 plugin_config *s = p->config_storage[i];
22550 for (j = 0; j < exts->used; j++) {
22551 fcgi_extension *ex;
22554 ex = exts->exts[j];
22557 for (n = 0; n < ex->used; n++) {
22559 fcgi_extension_host *host;
22562 host = ex->hosts[n];
22565 for (proc = host->first; proc; proc = proc->next) {
22566 if (proc->pid != 0) kill(proc->pid, SIGTERM);
22568 - if (proc->is_local &&
22570 + if (proc->is_local &&
22571 !buffer_is_empty(proc->unixsocket)) {
22572 unlink(proc->unixsocket->ptr);
22577 for (proc = host->unused_procs; proc; proc = proc->next) {
22578 if (proc->pid != 0) kill(proc->pid, SIGTERM);
22580 - if (proc->is_local &&
22582 + if (proc->is_local &&
22583 !buffer_is_empty(proc->unixsocket)) {
22584 unlink(proc->unixsocket->ptr);
22591 fastcgi_extensions_free(s->exts);
22592 array_free(s->ext_mapping);
22597 free(p->config_storage);
22604 return HANDLER_GO_ON;
22607 static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
22611 if (!key || !val) return -1;
22614 dst = malloc(key_len + val_len + 3);
22615 memcpy(dst, key, key_len);
22616 dst[key_len] = '=';
22617 /* add the \0 from the value */
22618 memcpy(dst + key_len + 1, val, val_len + 1);
22621 if (env->size == 0) {
22623 env->ptr = malloc(env->size * sizeof(*env->ptr));
22624 @@ -732,9 +733,9 @@
22626 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
22630 env->ptr[env->used++] = dst;
22636 @@ -753,15 +754,15 @@
22637 if (env->size == 0) {
22639 env->ptr = malloc(env->size * sizeof(*env->ptr));
22640 - } else if (env->size == env->used) {
22641 + } else if (env->size == env->used) {
22643 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
22649 env->ptr[env->used++] = start;
22652 start = b->ptr + i + 1;
22655 @@ -794,7 +795,7 @@
22659 -static int fcgi_spawn_connection(server *srv,
22660 +static int fcgi_spawn_connection(server *srv,
22662 fcgi_extension_host *host,
22664 @@ -806,31 +807,27 @@
22666 struct sockaddr_in fcgi_addr_in;
22667 struct sockaddr *fcgi_addr;
22678 if (p->conf.debug) {
22679 log_error_write(srv, __FILE__, __LINE__, "sdb",
22680 "new proc, socket:", proc->port, proc->unixsocket);
22684 if (!buffer_is_empty(proc->unixsocket)) {
22685 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
22688 #ifdef HAVE_SYS_UN_H
22689 fcgi_addr_un.sun_family = AF_UNIX;
22690 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
22694 servlen = SUN_LEN(&fcgi_addr_un);
22696 - /* stevens says: */
22697 - servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
22700 socket_type = AF_UNIX;
22701 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
22703 @@ -844,108 +841,108 @@
22706 fcgi_addr_in.sin_family = AF_INET;
22709 if (buffer_is_empty(host->host)) {
22710 fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
22712 struct hostent *he;
22715 /* set a usefull default */
22716 fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
22721 if (NULL == (he = gethostbyname(host->host->ptr))) {
22722 - log_error_write(srv, __FILE__, __LINE__,
22723 - "sdb", "gethostbyname failed: ",
22724 + log_error_write(srv, __FILE__, __LINE__,
22725 + "sdb", "gethostbyname failed: ",
22726 h_errno, host->host);
22731 if (he->h_addrtype != AF_INET) {
22732 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
22737 if (he->h_length != sizeof(struct in_addr)) {
22738 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
22743 memcpy(&(fcgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
22747 fcgi_addr_in.sin_port = htons(proc->port);
22748 servlen = sizeof(fcgi_addr_in);
22751 socket_type = AF_INET;
22752 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
22755 buffer_copy_string(proc->connection_name, "tcp:");
22756 buffer_append_string_buffer(proc->connection_name, host->host);
22757 buffer_append_string(proc->connection_name, ":");
22758 buffer_append_long(proc->connection_name, proc->port);
22762 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
22763 - log_error_write(srv, __FILE__, __LINE__, "ss",
22764 + log_error_write(srv, __FILE__, __LINE__, "ss",
22765 "failed:", strerror(errno));
22770 if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
22771 /* server is not up, spawn in */
22775 - if (errno != ENOENT &&
22777 + if (errno != ENOENT &&
22778 !buffer_is_empty(proc->unixsocket)) {
22779 unlink(proc->unixsocket->ptr);
22786 /* reopen socket */
22787 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
22788 - log_error_write(srv, __FILE__, __LINE__, "ss",
22789 + log_error_write(srv, __FILE__, __LINE__, "ss",
22790 "socket failed:", strerror(errno));
22796 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
22797 - log_error_write(srv, __FILE__, __LINE__, "ss",
22798 + log_error_write(srv, __FILE__, __LINE__, "ss",
22799 "socketsockopt failed:", strerror(errno));
22804 /* create socket */
22805 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
22806 - log_error_write(srv, __FILE__, __LINE__, "sbs",
22807 - "bind failed for:",
22808 + log_error_write(srv, __FILE__, __LINE__, "sbs",
22809 + "bind failed for:",
22810 proc->connection_name,
22816 if (-1 == listen(fcgi_fd, 1024)) {
22817 - log_error_write(srv, __FILE__, __LINE__, "ss",
22818 + log_error_write(srv, __FILE__, __LINE__, "ss",
22819 "listen failed:", strerror(errno));
22826 switch ((child = fork())) {
22834 /* create environment */
22843 @@ -955,18 +952,18 @@
22844 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
22849 /* we don't need the client socket */
22850 for (i = 3; i < 256; i++) {
22855 /* build clean environment */
22856 if (host->bin_env_copy->used) {
22857 for (i = 0; i < host->bin_env_copy->used; i++) {
22858 data_string *ds = (data_string *)host->bin_env_copy->data[i];
22862 if (NULL != (ge = getenv(ds->value->ptr))) {
22863 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
22865 @@ -974,39 +971,39 @@
22867 for (i = 0; environ[i]; i++) {
22871 if (NULL != (eq = strchr(environ[i], '='))) {
22872 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
22878 /* create environment */
22879 for (i = 0; i < host->bin_env->used; i++) {
22880 data_string *ds = (data_string *)host->bin_env->data[i];
22883 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
22887 for (i = 0; i < env.used; i++) {
22888 /* search for PHP_FCGI_CHILDREN */
22889 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
22893 /* not found, add a default */
22894 if (i == env.used) {
22895 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
22899 env.ptr[env.used] = NULL;
22901 parse_binpath(&arg, host->bin_path);
22904 /* chdir into the base of the bin-path,
22905 * search for the last / */
22906 if (NULL != (c = strrchr(arg.ptr[0], '/'))) {
22910 /* change to the physical directory */
22911 if (-1 == chdir(arg.ptr[0])) {
22913 @@ -1018,12 +1015,12 @@
22916 execve(arg.ptr[0], arg.ptr, env.ptr);
22918 - log_error_write(srv, __FILE__, __LINE__, "sbs",
22920 + log_error_write(srv, __FILE__, __LINE__, "sbs",
22921 "execve failed for:", host->bin_path, strerror(errno));
22930 @@ -1031,17 +1028,17 @@
22937 select(0, NULL, NULL, NULL, &tv);
22940 switch (waitpid(child, &status, WNOHANG)) {
22942 /* child still running after timeout, good */
22945 /* no PID found ? should never happen */
22946 - log_error_write(srv, __FILE__, __LINE__, "ss",
22947 + log_error_write(srv, __FILE__, __LINE__, "ss",
22948 "pid not found:", strerror(errno));
22951 @@ -1049,10 +1046,10 @@
22952 "the fastcgi-backend", host->bin_path, "failed to start:");
22953 /* the child should not terminate at all */
22954 if (WIFEXITED(status)) {
22955 - log_error_write(srv, __FILE__, __LINE__, "sdb",
22956 - "child exited with status",
22957 + log_error_write(srv, __FILE__, __LINE__, "sdb",
22958 + "child exited with status",
22959 WEXITSTATUS(status), host->bin_path);
22960 - log_error_write(srv, __FILE__, __LINE__, "s",
22961 + log_error_write(srv, __FILE__, __LINE__, "s",
22962 "if you try do run PHP as FastCGI backend make sure you use the FastCGI enabled version.\n"
22963 "You can find out if it is the right one by executing 'php -v' and it should display '(cgi-fcgi)' "
22964 "in the output, NOT (cgi) NOR (cli)\n"
22965 @@ -1060,8 +1057,8 @@
22966 log_error_write(srv, __FILE__, __LINE__, "s",
22967 "If this is PHP on Gentoo add fastcgi to the USE flags");
22968 } else if (WIFSIGNALED(status)) {
22969 - log_error_write(srv, __FILE__, __LINE__, "sd",
22970 - "terminated by signal:",
22971 + log_error_write(srv, __FILE__, __LINE__, "sd",
22972 + "terminated by signal:",
22975 if (WTERMSIG(status) == 11) {
22976 @@ -1071,8 +1068,8 @@
22977 "If this is PHP try to remove the byte-code caches for now and try again.");
22980 - log_error_write(srv, __FILE__, __LINE__, "sd",
22981 - "child died somehow:",
22982 + log_error_write(srv, __FILE__, __LINE__, "sd",
22983 + "child died somehow:",
22987 @@ -1082,26 +1079,26 @@
22989 proc->last_used = srv->cur_ts;
22990 proc->is_local = 1;
22997 proc->is_local = 0;
23001 if (p->conf.debug) {
23002 log_error_write(srv, __FILE__, __LINE__, "sb",
23003 "(debug) socket is already used, won't spawn:",
23004 proc->connection_name);
23009 proc->state = PROC_STATE_RUNNING;
23010 host->active_procs++;
23019 @@ -1111,93 +1108,93 @@
23022 buffer *fcgi_mode = buffer_init();
23024 - config_values_t cv[] = {
23026 + config_values_t cv[] = {
23027 { "fastcgi.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
23028 { "fastcgi.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
23029 { "fastcgi.map-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
23030 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
23034 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
23037 for (i = 0; i < srv->config_context->used; i++) {
23042 s = malloc(sizeof(plugin_config));
23043 s->exts = fastcgi_extensions_init();
23045 s->ext_mapping = array_init();
23048 cv[0].destination = s->exts;
23049 cv[1].destination = &(s->debug);
23050 cv[2].destination = s->ext_mapping;
23053 p->config_storage[i] = s;
23054 ca = ((data_config *)srv->config_context->data[i])->value;
23057 if (0 != config_insert_values_global(srv, ca, cv)) {
23058 return HANDLER_ERROR;
23068 if (NULL != (du = array_get_element(ca, "fastcgi.server"))) {
23070 data_array *da = (data_array *)du;
23073 if (du->type != TYPE_ARRAY) {
23074 - log_error_write(srv, __FILE__, __LINE__, "sss",
23075 + log_error_write(srv, __FILE__, __LINE__, "sss",
23076 "unexpected type for key: ", "fastcgi.server", "array of strings");
23079 return HANDLER_ERROR;
23084 - * fastcgi.server = ( "<ext>" => ( ... ),
23088 + * fastcgi.server = ( "<ext>" => ( ... ),
23089 * "<ext>" => ( ... ) )
23093 for (j = 0; j < da->value->used; j++) {
23095 data_array *da_ext = (data_array *)da->value->data[j];
23098 if (da->value->data[j]->type != TYPE_ARRAY) {
23099 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
23100 - "unexpected type for key: ", "fastcgi.server",
23101 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
23102 + "unexpected type for key: ", "fastcgi.server",
23103 "[", da->value->data[j]->key, "](string)");
23106 return HANDLER_ERROR;
23110 - * da_ext->key == name of the extension
23113 + * da_ext->key == name of the extension
23117 - * fastcgi.server = ( "<ext>" =>
23118 - * ( "<host>" => ( ... ),
23121 + * fastcgi.server = ( "<ext>" =>
23122 + * ( "<host>" => ( ... ),
23123 * "<host>" => ( ... )
23130 for (n = 0; n < da_ext->value->used; n++) {
23131 data_array *da_host = (data_array *)da_ext->value->data[n];
23134 fcgi_extension_host *host;
23136 - config_values_t fcv[] = {
23138 + config_values_t fcv[] = {
23139 { "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
23140 { "docroot", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
23141 { "mode", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
23142 { "socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
23143 { "bin-path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
23146 { "check-local", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
23147 { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
23148 { "min-procs-not-working", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 this is broken for now */
23149 @@ -1205,28 +1202,28 @@
23150 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
23151 { "idle-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
23152 { "disable-time", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
23155 { "bin-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
23156 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
23159 { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
23160 { "allow-x-send-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */
23161 { "strip-request-uri", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 16 */
23164 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
23168 if (da_host->type != TYPE_ARRAY) {
23169 - log_error_write(srv, __FILE__, __LINE__, "ssSBS",
23170 - "unexpected type for key:",
23171 - "fastcgi.server",
23172 + log_error_write(srv, __FILE__, __LINE__, "ssSBS",
23173 + "unexpected type for key:",
23174 + "fastcgi.server",
23175 "[", da_host->key, "](string)");
23178 return HANDLER_ERROR;
23182 host = fastcgi_host_init();
23185 buffer_copy_string_buffer(host->id, da_host->key);
23187 host->check_local = 1;
23188 @@ -1238,13 +1235,13 @@
23189 host->disable_time = 60;
23190 host->break_scriptfilename_for_php = 0;
23191 host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
23194 fcv[0].destination = host->host;
23195 fcv[1].destination = host->docroot;
23196 fcv[2].destination = fcgi_mode;
23197 fcv[3].destination = host->unixsocket;
23198 fcv[4].destination = host->bin_path;
23201 fcv[5].destination = &(host->check_local);
23202 fcv[6].destination = &(host->port);
23203 fcv[7].destination = &(host->min_procs);
23204 @@ -1252,35 +1249,35 @@
23205 fcv[9].destination = &(host->max_load_per_proc);
23206 fcv[10].destination = &(host->idle_timeout);
23207 fcv[11].destination = &(host->disable_time);
23210 fcv[12].destination = host->bin_env;
23211 fcv[13].destination = host->bin_env_copy;
23212 fcv[14].destination = &(host->break_scriptfilename_for_php);
23213 fcv[15].destination = &(host->allow_xsendfile);
23214 fcv[16].destination = host->strip_request_uri;
23217 if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
23218 return HANDLER_ERROR;
23221 - if ((!buffer_is_empty(host->host) || host->port) &&
23223 + if ((!buffer_is_empty(host->host) || host->port) &&
23224 !buffer_is_empty(host->unixsocket)) {
23225 - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23226 + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23227 "either host/port or socket have to be set in:",
23230 da_ext->key, " => (",
23231 da_host->key, " ( ...");
23233 return HANDLER_ERROR;
23237 if (!buffer_is_empty(host->unixsocket)) {
23238 /* unix domain socket */
23241 if (host->unixsocket->used > UNIX_PATH_MAX - 2) {
23242 - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23243 + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23244 "unixsocket is too long in:",
23247 da_ext->key, " => (",
23248 da_host->key, " ( ...");
23250 @@ -1288,37 +1285,37 @@
23255 - if (buffer_is_empty(host->host) &&
23257 + if (buffer_is_empty(host->host) &&
23258 buffer_is_empty(host->bin_path)) {
23259 - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23260 + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23261 "host or binpath have to be set in:",
23264 da_ext->key, " => (",
23265 da_host->key, " ( ...");
23268 return HANDLER_ERROR;
23269 } else if (host->port == 0) {
23270 - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23271 + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23272 "port has to be set in:",
23275 da_ext->key, " => (",
23276 da_host->key, " ( ...");
23278 return HANDLER_ERROR;
23282 - if (!buffer_is_empty(host->bin_path)) {
23284 + if (!buffer_is_empty(host->bin_path)) {
23285 /* a local socket + self spawning */
23288 /* HACK: just to make sure the adaptive spawing is disabled */
23289 host->min_procs = host->max_procs;
23292 if (host->min_procs > host->max_procs) host->max_procs = host->min_procs;
23293 if (host->max_load_per_proc < 1) host->max_load_per_proc = 0;
23297 log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
23298 "--- fastcgi spawning local",
23299 @@ -1328,7 +1325,7 @@
23300 "\n\tmin-procs:", host->min_procs,
23301 "\n\tmax-procs:", host->max_procs);
23305 for (pno = 0; pno < host->min_procs; pno++) {
23308 @@ -1343,7 +1340,7 @@
23309 buffer_append_string(proc->unixsocket, "-");
23310 buffer_append_long(proc->unixsocket, pno);
23315 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
23316 "--- fastcgi spawning",
23317 @@ -1351,7 +1348,7 @@
23318 "\n\tsocket", host->unixsocket,
23319 "\n\tcurrent:", pno, "/", host->min_procs);
23323 if (fcgi_spawn_connection(srv, p, host, proc)) {
23324 log_error_write(srv, __FILE__, __LINE__, "s",
23325 "[ERROR]: spawning fcgi failed.");
23326 @@ -1359,35 +1356,35 @@
23329 fastcgi_status_init(srv, p->statuskey, host, proc);
23332 proc->next = host->first;
23333 if (host->first) host->first->prev = proc;
23336 host->first = proc;
23342 proc = fastcgi_process_init();
23343 proc->id = host->num_procs++;
23345 host->active_procs++;
23346 proc->state = PROC_STATE_RUNNING;
23349 if (buffer_is_empty(host->unixsocket)) {
23350 proc->port = host->port;
23352 buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
23356 fastcgi_status_init(srv, p->statuskey, host, proc);
23358 host->first = proc;
23361 host->min_procs = 1;
23362 host->max_procs = 1;
23366 if (!buffer_is_empty(fcgi_mode)) {
23367 if (strcmp(fcgi_mode->ptr, "responder") == 0) {
23368 host->mode = FCGI_RESPONDER;
23369 @@ -1411,16 +1408,16 @@
23375 buffer_free(fcgi_mode);
23378 return HANDLER_GO_ON;
23381 static int fcgi_set_state(server *srv, handler_ctx *hctx, fcgi_connection_state_t state) {
23382 hctx->state = state;
23383 hctx->state_timestamp = srv->cur_ts;
23389 @@ -1429,13 +1426,13 @@
23392 buffer_uint *r = &(p->fcgi_request_id);
23397 for (i = 0; i < r->used; i++) {
23398 if (r->ptr[i] > m) m = r->ptr[i];
23402 if (r->size == 0) {
23404 r->ptr = malloc(sizeof(*r->ptr) * r->size);
23405 @@ -1443,54 +1440,55 @@
23407 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
23411 r->ptr[r->used++] = ++m;
23417 static int fcgi_requestid_del(server *srv, plugin_data *p, size_t request_id) {
23419 buffer_uint *r = &(p->fcgi_request_id);
23424 for (i = 0; i < r->used; i++) {
23425 if (r->ptr[i] == request_id) break;
23429 if (i != r->used) {
23433 if (i != r->used - 1) {
23434 r->ptr[i] = r->ptr[r->used - 1];
23442 void fcgi_connection_close(server *srv, handler_ctx *hctx) {
23447 if (NULL == hctx) return;
23450 p = hctx->plugin_data;
23451 con = hctx->remote_conn;
23454 if (con->mode != p->id) {
23459 - if (hctx->fd != -1) {
23460 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
23461 - fdevent_unregister(srv->ev, hctx->fd);
23465 + if (hctx->sock->fd != -1) {
23466 + fdevent_event_del(srv->ev, hctx->sock);
23467 + fdevent_unregister(srv->ev, hctx->sock);
23468 + closesocket(hctx->sock->fd);
23469 + hctx->sock->fd = -1;
23475 if (hctx->request_id != 0) {
23476 fcgi_requestid_del(srv, p, hctx->request_id);
23478 @@ -1499,7 +1497,7 @@
23479 if (hctx->got_proc) {
23480 /* after the connect the process gets a load */
23481 hctx->proc->load--;
23484 status_counter_dec(srv, CONST_STR_LEN("fastcgi.active-requests"));
23486 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
23487 @@ -1509,101 +1507,101 @@
23489 if (p->conf.debug) {
23490 log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
23491 - "released proc:",
23492 - "pid:", hctx->proc->pid,
23493 - "socket:", hctx->proc->connection_name,
23494 + "released proc:",
23495 + "pid:", hctx->proc->pid,
23496 + "socket:", hctx->proc->connection_name,
23497 "load:", hctx->proc->load);
23504 handler_ctx_free(hctx);
23505 - con->plugin_ctx[p->id] = NULL;
23506 + con->plugin_ctx[p->id] = NULL;
23509 static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
23510 plugin_data *p = hctx->plugin_data;
23521 * connect was ok, connection was accepted
23522 * but the php accept loop checks after the accept if it should die or not.
23524 - * if yes we can only detect it at a write()
23527 + * if yes we can only detect it at a write()
23529 * next step is resetting this attemp and setup a connection again
23532 * if we have more then 5 reconnects for the same request, die
23539 * we have a connection but the child died by some other reason
23544 - if (hctx->fd != -1) {
23545 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
23546 - fdevent_unregister(srv->ev, hctx->fd);
23548 + if (hctx->sock->fd != -1) {
23549 + fdevent_event_del(srv->ev, hctx->sock);
23550 + fdevent_unregister(srv->ev, hctx->sock);
23551 + close(hctx->sock->fd);
23554 + hctx->sock->fd = -1;
23558 fcgi_requestid_del(srv, p, hctx->request_id);
23561 fcgi_set_state(srv, hctx, FCGI_STATE_INIT);
23564 hctx->request_id = 0;
23565 hctx->reconnects++;
23568 if (p->conf.debug > 2) {
23570 log_error_write(srv, __FILE__, __LINE__, "sdb",
23571 - "release proc for reconnect:",
23572 + "release proc for reconnect:",
23573 hctx->proc->pid, hctx->proc->connection_name);
23575 log_error_write(srv, __FILE__, __LINE__, "sb",
23576 - "release proc for reconnect:",
23577 + "release proc for reconnect:",
23578 hctx->host->unixsocket);
23582 - if (hctx->proc && hctx->got_proc) {
23583 + if (hctx->proc && hctx->got_proc) {
23584 hctx->proc->load--;
23587 /* perhaps another host gives us more luck */
23588 hctx->host->load--;
23596 static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) {
23597 plugin_data *p = p_d;
23600 fcgi_connection_close(srv, con->plugin_ctx[p->id]);
23603 return HANDLER_GO_ON;
23607 static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
23611 if (!key || !val) return -1;
23614 len = key_len + val_len;
23617 len += key_len > 127 ? 4 : 1;
23618 len += val_len > 127 ? 4 : 1;
23621 buffer_prepare_append(env, len);
23624 if (key_len > 127) {
23625 env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80;
23626 env->ptr[env->used++] = (key_len >> 16) & 0xff;
23627 @@ -1612,7 +1610,7 @@
23629 env->ptr[env->used++] = (key_len >> 0) & 0xff;
23633 if (val_len > 127) {
23634 env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80;
23635 env->ptr[env->used++] = (val_len >> 16) & 0xff;
23636 @@ -1621,12 +1619,12 @@
23638 env->ptr[env->used++] = (val_len >> 0) & 0xff;
23642 memcpy(env->ptr + env->used, key, key_len);
23643 env->used += key_len;
23644 memcpy(env->ptr + env->used, val, val_len);
23645 env->used += val_len;
23651 @@ -1639,11 +1637,11 @@
23652 header->contentLengthB1 = (contentLength >> 8) & 0xff;
23653 header->paddingLength = paddingLength;
23654 header->reserved = 0;
23665 @@ -1665,26 +1663,23 @@
23666 struct sockaddr_un fcgi_addr_un;
23671 fcgi_extension_host *host = hctx->host;
23672 fcgi_proc *proc = hctx->proc;
23673 - int fcgi_fd = hctx->fd;
23675 + int fcgi_fd = hctx->sock->fd;
23677 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
23680 if (!buffer_is_empty(proc->unixsocket)) {
23681 #ifdef HAVE_SYS_UN_H
23682 /* use the unix domain socket */
23683 fcgi_addr_un.sun_family = AF_UNIX;
23684 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
23687 servlen = SUN_LEN(&fcgi_addr_un);
23689 - /* stevens says: */
23690 - servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
23693 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
23696 if (buffer_is_empty(proc->connection_name)) {
23697 /* on remote spawing we have to set the connection-name now */
23698 buffer_copy_string(proc->connection_name, "unix:");
23699 @@ -1695,16 +1690,18 @@
23702 fcgi_addr_in.sin_family = AF_INET;
23704 if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) {
23705 - log_error_write(srv, __FILE__, __LINE__, "sbs",
23706 - "converting IP-adress failed for", host->host,
23707 + log_error_write(srv, __FILE__, __LINE__, "sbs",
23708 + "converting IP-adress failed for", host->host,
23709 "\nBe sure to specify an IP address here");
23715 fcgi_addr_in.sin_port = htons(proc->port);
23716 servlen = sizeof(fcgi_addr_in);
23719 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
23721 if (buffer_is_empty(proc->connection_name)) {
23722 @@ -1715,20 +1712,20 @@
23723 buffer_append_long(proc->connection_name, proc->port);
23728 if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
23729 - if (errno == EINPROGRESS ||
23730 + if (errno == EINPROGRESS ||
23731 errno == EALREADY ||
23733 if (hctx->conf.debug > 2) {
23734 - log_error_write(srv, __FILE__, __LINE__, "sb",
23735 + log_error_write(srv, __FILE__, __LINE__, "sb",
23736 "connect delayed, will continue later:", proc->connection_name);
23740 return CONNECTION_DELAYED;
23741 } else if (errno == EAGAIN) {
23742 if (hctx->conf.debug) {
23743 - log_error_write(srv, __FILE__, __LINE__, "sbsd",
23744 + log_error_write(srv, __FILE__, __LINE__, "sbsd",
23745 "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
23746 "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
23747 "The load for this fastcgi backend", proc->connection_name, "is", proc->load);
23748 @@ -1736,8 +1733,8 @@
23750 return CONNECTION_OVERLOADED;
23752 - log_error_write(srv, __FILE__, __LINE__, "sssb",
23753 - "connect failed:",
23754 + log_error_write(srv, __FILE__, __LINE__, "sssb",
23755 + "connect failed:",
23756 strerror(errno), "on",
23757 proc->connection_name);
23759 @@ -1747,7 +1744,7 @@
23761 hctx->reconnects = 0;
23762 if (hctx->conf.debug > 1) {
23763 - log_error_write(srv, __FILE__, __LINE__, "sd",
23764 + log_error_write(srv, __FILE__, __LINE__, "sd",
23765 "connect succeeded: ", fcgi_fd);
23768 @@ -1756,21 +1753,21 @@
23770 static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
23774 for (i = 0; i < con->request.headers->used; i++) {
23778 ds = (data_string *)con->request.headers->data[i];
23781 if (ds->value->used && ds->key->used) {
23783 buffer_reset(srv->tmp_buf);
23786 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
23787 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
23788 srv->tmp_buf->used--;
23792 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
23793 for (j = 0; j < ds->key->used - 1; j++) {
23795 @@ -1784,20 +1781,20 @@
23796 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
23798 srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
23801 fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
23806 for (i = 0; i < con->environment->used; i++) {
23810 ds = (data_string *)con->environment->data[i];
23813 if (ds->value->used && ds->key->used) {
23815 buffer_reset(srv->tmp_buf);
23818 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
23819 for (j = 0; j < ds->key->used - 1; j++) {
23821 @@ -1811,11 +1808,11 @@
23822 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
23824 srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
23827 fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
23835 @@ -1824,24 +1821,24 @@
23836 FCGI_BeginRequestRecord beginRecord;
23837 FCGI_Header header;
23844 char b2[INET6_ADDRSTRLEN + 1];
23848 plugin_data *p = hctx->plugin_data;
23849 fcgi_extension_host *host= hctx->host;
23851 connection *con = hctx->remote_conn;
23852 server_socket *srv_sock = con->srv_socket;
23855 sock_addr our_addr;
23856 socklen_t our_addr_len;
23859 /* send FCGI_BEGIN_REQUEST */
23862 fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, request_id, sizeof(beginRecord.body), 0);
23863 beginRecord.body.roleB0 = host->mode;
23864 beginRecord.body.roleB1 = 0;
23865 @@ -1849,21 +1846,21 @@
23866 memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
23868 b = chunkqueue_get_append_buffer(hctx->wb);
23871 buffer_copy_memory(b, (const char *)&beginRecord, sizeof(beginRecord));
23874 /* send FCGI_PARAMS */
23875 buffer_prepare_copy(p->fcgi_env, 1024);
23878 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
23881 if (con->server_name->used) {
23882 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
23885 - s = inet_ntop(srv_sock->addr.plain.sa_family,
23886 - srv_sock->addr.plain.sa_family == AF_INET6 ?
23887 + s = inet_ntop(srv_sock->addr.plain.sa_family,
23888 + srv_sock->addr.plain.sa_family == AF_INET6 ?
23889 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
23890 (const void *) &(srv_sock->addr.ipv4.sin_addr),
23892 @@ -1872,50 +1869,50 @@
23894 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
23898 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
23904 ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
23906 ntohs(srv_sock->addr.ipv4.sin_port)
23911 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
23914 /* get the server-side of the connection to the client */
23915 our_addr_len = sizeof(our_addr);
23917 - if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
23919 + if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
23920 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
23922 s = inet_ntop_cache_get_ip(srv, &(our_addr));
23924 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
23930 ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
23932 ntohs(con->dst_addr.ipv4.sin_port)
23937 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
23940 s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
23941 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
23944 if (!buffer_is_empty(con->authed_user)) {
23945 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_USER"),
23946 CONST_BUF_LEN(con->authed_user));
23950 if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) {
23951 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
23954 /* request.content_length < SSIZE_MAX, see request.c */
23955 ltostr(buf, con->request.content_length);
23956 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
23957 @@ -1930,12 +1927,12 @@
23960 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
23963 if (!buffer_is_empty(con->request.pathinfo)) {
23964 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
23967 /* PATH_TRANSLATED is only defined if PATH_INFO is set */
23970 if (!buffer_is_empty(host->docroot)) {
23971 buffer_copy_string_buffer(p->path, host->docroot);
23973 @@ -1957,27 +1954,27 @@
23976 if (!buffer_is_empty(host->docroot)) {
23978 - * rewrite SCRIPT_FILENAME
23981 + * rewrite SCRIPT_FILENAME
23986 buffer_copy_string_buffer(p->path, host->docroot);
23987 buffer_append_string_buffer(p->path, con->uri.path);
23990 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
23991 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
23993 buffer_copy_string_buffer(p->path, con->physical.path);
23995 - /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
23998 + /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
24000 * see src/sapi/cgi_main.c, init_request_info()
24002 if (host->break_scriptfilename_for_php) {
24003 buffer_append_string_buffer(p->path, con->request.pathinfo);
24007 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
24008 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
24010 @@ -1987,7 +1984,7 @@
24014 - * stripping /app1 or /app1/ should lead to
24015 + * stripping /app1 or /app1/ should lead to
24019 @@ -2001,7 +1998,7 @@
24020 0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, host->strip_request_uri->used - 1)) {
24021 /* the left is the same */
24023 - fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
24024 + fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
24025 con->request.orig_uri->ptr + (host->strip_request_uri->used - 2),
24026 con->request.orig_uri->used - (host->strip_request_uri->used - 2));
24028 @@ -2018,26 +2015,26 @@
24030 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
24034 s = get_http_method_name(con->request.http_method);
24035 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
24036 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
24037 s = get_http_version_name(con->request.http_version);
24038 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
24042 if (srv_sock->is_ssl) {
24043 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
24050 fcgi_env_add_request_headers(srv, con, p);
24053 fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0);
24054 buffer_append_memory(b, (const char *)&header, sizeof(header));
24055 buffer_append_memory(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used);
24058 fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
24059 buffer_append_memory(b, (const char *)&header, sizeof(header));
24061 @@ -2057,7 +2054,7 @@
24063 /* we announce toWrite octects
24064 * now take all the request_content chunk that we need to fill this request
24068 b = chunkqueue_get_append_buffer(hctx->wb);
24069 fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0);
24070 @@ -2080,16 +2077,16 @@
24071 if (weHave > weWant - written) weHave = weWant - written;
24073 if (p->conf.debug > 10) {
24074 - fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n",
24075 - __FILE__, __LINE__,
24078 - req_c->file.length,
24079 + fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n",
24080 + __FILE__, __LINE__,
24083 + req_c->file.length,
24084 req_c->file.name->ptr);
24087 assert(weHave != 0);
24090 chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
24092 req_c->offset += weHave;
24093 @@ -2104,7 +2101,7 @@
24094 * - we reference the tempfile from the request-content-queue several times
24095 * if the req_c is larger than FCGI_MAX_LENGTH
24096 * - we can't simply cleanup the request-content-queue as soon as possible
24097 - * as it would remove the tempfiles
24098 + * as it would remove the tempfiles
24099 * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last
24100 * referencing chunk of the fastcgi-write-queue
24102 @@ -2141,7 +2138,7 @@
24103 req_c->offset += weHave;
24104 req_cq->bytes_out += weHave;
24108 hctx->wb->bytes_in += weHave;
24110 if (req_c->offset == req_c->mem->used - 1) {
24111 @@ -2155,12 +2152,12 @@
24117 b->used++; /* add virtual \0 */
24123 b = chunkqueue_get_append_buffer(hctx->wb);
24124 /* terminate STDIN */
24125 fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0);
24126 @@ -2175,118 +2172,19 @@
24127 if ((i+1) % 16 == 0) {
24129 for (j = i-15; j <= i; j++) {
24130 - fprintf(stderr, "%c",
24131 + fprintf(stderr, "%c",
24132 isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
24134 fprintf(stderr, "\n");
24142 -static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
24145 - handler_ctx *hctx = con->plugin_ctx[p->id];
24146 - fcgi_extension_host *host= hctx->host;
24150 - buffer_copy_string_buffer(p->parse_response, in);
24152 - /* search for \n */
24153 - for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {
24154 - char *key, *value;
24158 - /* a good day. Someone has read the specs and is sending a \r\n to us */
24160 - if (ns > p->parse_response->ptr &&
24161 - *(ns-1) == '\r') {
24168 - if (NULL == (value = strchr(s, ':'))) {
24169 - /* we expect: "<key>: <value>\n" */
24173 - key_len = value - key;
24177 - while (*value == ' ' || *value == '\t') value++;
24179 - if (host->mode != FCGI_AUTHORIZER ||
24180 - !(con->http_status == 0 ||
24181 - con->http_status == 200)) {
24182 - /* authorizers shouldn't affect the response headers sent back to the client */
24184 - /* don't forward Status: */
24185 - if (0 != strncasecmp(key, "Status", key_len)) {
24186 - if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
24187 - ds = data_response_init();
24189 - buffer_copy_string_len(ds->key, key, key_len);
24190 - buffer_copy_string(ds->value, value);
24192 - array_insert_unique(con->response.headers, (data_unset *)ds);
24196 - switch(key_len) {
24198 - if (0 == strncasecmp(key, "Date", key_len)) {
24199 - con->parsed_response |= HTTP_DATE;
24203 - if (0 == strncasecmp(key, "Status", key_len)) {
24204 - con->http_status = strtol(value, NULL, 10);
24205 - con->parsed_response |= HTTP_STATUS;
24209 - if (0 == strncasecmp(key, "Location", key_len)) {
24210 - con->parsed_response |= HTTP_LOCATION;
24214 - if (0 == strncasecmp(key, "Connection", key_len)) {
24215 - con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
24216 - con->parsed_response |= HTTP_CONNECTION;
24220 - if (0 == strncasecmp(key, "Content-Length", key_len)) {
24221 - con->response.content_length = strtol(value, NULL, 10);
24222 - con->parsed_response |= HTTP_CONTENT_LENGTH;
24224 - if (con->response.content_length < 0) con->response.content_length = 0;
24232 - /* CGI/1.1 rev 03 - 7.2.1.2 */
24233 - if ((con->parsed_response & HTTP_LOCATION) &&
24234 - !(con->parsed_response & HTTP_STATUS)) {
24235 - con->http_status = 302;
24247 @@ -2327,9 +2225,9 @@
24251 - /* we have at least a header, now check how much me have to fetch */
24252 + /* we have at least a header, now check how much me have to fetch */
24253 header = (FCGI_Header *)(packet->b->ptr);
24256 packet->len = (header->contentLengthB0 | (header->contentLengthB1 << 8)) + header->paddingLength;
24257 packet->request_id = (header->requestIdB0 | (header->requestIdB1 << 8));
24258 packet->type = header->type;
24259 @@ -2348,7 +2246,7 @@
24260 size_t weHave = c->mem->used - c->offset - offset - 1;
24262 if (weHave > weWant) weHave = weWant;
24265 buffer_append_string_len(packet->b, c->mem->ptr + c->offset + offset, weHave);
24267 /* we only skipped the first 8 bytes as they are the fcgi header */
24268 @@ -2380,65 +2278,42 @@
24271 chunkqueue_remove_finished_chunks(hctx->rb);
24277 static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
24283 plugin_data *p = hctx->plugin_data;
24284 connection *con = hctx->remote_conn;
24285 - int fcgi_fd = hctx->fd;
24286 fcgi_extension_host *host= hctx->host;
24287 fcgi_proc *proc = hctx->proc;
24290 - * check how much we have to read
24292 - if (ioctl(hctx->fd, FIONREAD, &toread)) {
24293 - log_error_write(srv, __FILE__, __LINE__, "sd",
24294 - "unexpected end-of-file (perhaps the fastcgi process died):",
24299 - /* init read-buffer */
24301 - if (toread > 0) {
24304 - b = chunkqueue_get_append_buffer(hctx->rb);
24305 - buffer_prepare_copy(b, toread + 1);
24307 - /* append to read-buffer */
24308 - if (-1 == (r = read(hctx->fd, b->ptr, toread))) {
24309 - log_error_write(srv, __FILE__, __LINE__, "sds",
24310 - "unexpected end-of-file (perhaps the fastcgi process died):",
24311 - fcgi_fd, strerror(errno));
24315 - /* this should be catched by the b > 0 above */
24319 - b->used = r + 1; /* one extra for the fake \0 */
24320 - b->ptr[b->used - 1] = '\0';
24322 - log_error_write(srv, __FILE__, __LINE__, "ssdsb",
24323 - "unexpected end-of-file (perhaps the fastcgi process died):",
24324 - "pid:", proc->pid,
24325 - "socket:", proc->connection_name);
24327 + /* in case we read nothing, check the return code
24328 + * if we got something, be happy :)
24330 + * Ok, to be honest:
24331 + * - it is fine to receive a EAGAIN on a second read() call
24332 + * - it might be fine they we get a con-close on a second read() call */
24333 + switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
24334 + case NETWORK_STATUS_WAIT_FOR_EVENT:
24335 + /* a EAGAIN after we read exactly the chunk-size */
24337 + ERROR("%s", "oops, got a EAGAIN even if we just got call for the event, wired");
24339 + case NETWORK_STATUS_SUCCESS:
24342 + ERROR("reading from fastcgi socket failed (fd=%d)", hctx->sock->fd);
24347 * parse the fastcgi packets and forward the content to the write-queue
24352 fastcgi_response_packet packet;
24354 @@ -2454,92 +2329,136 @@
24356 /* is the header already finished */
24357 if (0 == con->file_started) {
24362 - /* search for header terminator
24364 - * if we start with \r\n check if last packet terminated with \r\n
24365 - * if we start with \n check if last packet terminated with \n
24366 - * search for \r\n\r\n
24367 - * search for \n\n
24370 - if (hctx->response_header->used == 0) {
24371 - buffer_copy_string_buffer(hctx->response_header, packet.b);
24373 - buffer_append_string_buffer(hctx->response_header, packet.b);
24376 - if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) {
24377 - blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 4;
24378 - hctx->response_header->used = (c - hctx->response_header->ptr) + 3;
24379 - c += 4; /* point the the start of the response */
24380 - } else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) {
24381 - blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 2;
24382 - hctx->response_header->used = c - hctx->response_header->ptr + 2;
24383 - c += 2; /* point the the start of the response */
24385 - /* no luck, no header found */
24386 + int have_content_length = 0;
24387 + int need_more = 0;
24390 + /* append the current packet to the chunk queue */
24391 + chunkqueue_append_buffer(hctx->http_rb, packet.b);
24392 + http_response_reset(p->resp);
24394 + switch(http_response_parse_cq(hctx->http_rb, p->resp)) {
24395 + case PARSE_ERROR:
24396 + /* parsing the response header failed */
24398 + con->http_status = 502; /* Bad Gateway */
24401 + case PARSE_NEED_MORE:
24403 + break; /* leave the loop */
24404 + case PARSE_SUCCESS:
24407 + /* should not happen */
24411 - /* parse the response header */
24412 - fcgi_response_parse(srv, con, p, hctx->response_header);
24413 + if (need_more) break;
24415 - con->file_started = 1;
24416 + chunkqueue_remove_finished_chunks(hctx->http_rb);
24418 + con->http_status = p->resp->status;
24419 + hctx->send_content_body = 1;
24421 - if (host->mode == FCGI_AUTHORIZER &&
24422 - (con->http_status == 0 ||
24423 - con->http_status == 200)) {
24424 - /* a authorizer with approved the static request, ignore the content here */
24425 - hctx->send_content_body = 0;
24428 - if (host->allow_xsendfile &&
24429 - NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))) {
24430 - stat_cache_entry *sce;
24432 - if (HANDLER_ERROR != stat_cache_get_entry(srv, con, ds->value, &sce)) {
24435 - http_chunk_append_file(srv, con, ds->value, 0, sce->st.st_size);
24436 - hctx->send_content_body = 0; /* ignore the content */
24437 - joblist_append(srv, con);
24438 + /* handle the header fields */
24439 + if (host->mode == FCGI_AUTHORIZER) {
24440 + /* auth mode is a bit different */
24442 + if (con->http_status == 0 ||
24443 + con->http_status == 200) {
24444 + /* a authorizer with approved the static request, ignore the content here */
24445 + hctx->send_content_body = 0;
24449 + /* copy the http-headers */
24450 + for (i = 0; i < p->resp->headers->used; i++) {
24451 + const char *ign[] = { "Status", NULL };
24455 + data_string *header = (data_string *)p->resp->headers->data[i];
24457 + /* ignore all headers in AUTHORIZER mode */
24458 + if (host->mode == FCGI_AUTHORIZER) continue;
24460 + /* some headers are ignored by default */
24461 + for (j = 0; ign[j]; j++) {
24462 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
24464 + if (ign[j]) continue;
24466 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
24467 + /* CGI/1.1 rev 03 - 7.2.1.2 */
24468 + con->http_status = 302;
24469 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
24470 + have_content_length = 1;
24471 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Sendfile")) ||
24472 + 0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-LIGHTTPD-send-file"))) {
24474 + stat_cache_entry *sce;
24476 - if (hctx->send_content_body && blen > 1) {
24477 - /* enable chunked-transfer-encoding */
24478 + if (host->allow_xsendfile &&
24479 + HANDLER_ERROR != stat_cache_get_entry(srv, con, header->value, &sce)) {
24480 + http_chunk_append_file(srv, con, header->value, 0, sce->st.st_size);
24481 + hctx->send_content_body = 0; /* ignore the content */
24483 + joblist_append(srv, con);
24486 + continue; /* ignore header */
24489 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
24490 + ds = data_response_init();
24492 + buffer_copy_string_buffer(ds->key, header->key);
24493 + buffer_copy_string_buffer(ds->value, header->value);
24495 + array_insert_unique(con->response.headers, (data_unset *)ds);
24498 + /* header is complete ... go on with the body */
24500 + con->file_started = 1;
24502 + if (hctx->send_content_body) {
24503 + chunk *c = hctx->http_rb->first;
24505 + /* if we don't have a content-length enable chunked encoding
24508 + * TODO: move this to a later stage in the filter-queue
24510 if (con->request.http_version == HTTP_VERSION_1_1 &&
24511 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
24512 + !have_content_length) {
24513 con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
24516 - http_chunk_append_mem(srv, con, c, blen);
24517 + /* copy the rest of the data */
24518 + for (c = hctx->http_rb->first; c; c = c->next) {
24519 + if (c->mem->used > 1) {
24520 + http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
24521 + c->offset = c->mem->used - 1;
24524 + chunkqueue_remove_finished_chunks(hctx->http_rb);
24525 joblist_append(srv, con);
24527 } else if (hctx->send_content_body && packet.b->used > 1) {
24528 - if (con->request.http_version == HTTP_VERSION_1_1 &&
24529 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
24530 - /* enable chunked-transfer-encoding */
24531 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
24534 http_chunk_append_mem(srv, con, packet.b->ptr, packet.b->used);
24535 joblist_append(srv, con);
24539 - log_error_write(srv, __FILE__, __LINE__, "sb",
24540 + log_error_write(srv, __FILE__, __LINE__, "sb",
24541 "FastCGI-stderr:", packet.b);
24545 case FCGI_END_REQUEST:
24546 con->file_finished = 1;
24549 if (host->mode != FCGI_AUTHORIZER ||
24550 !(con->http_status == 0 ||
24551 con->http_status == 200)) {
24552 @@ -2547,39 +2466,39 @@
24553 http_chunk_append_mem(srv, con, NULL, 0);
24554 joblist_append(srv, con);
24561 - log_error_write(srv, __FILE__, __LINE__, "sd",
24562 + log_error_write(srv, __FILE__, __LINE__, "sd",
24563 "FastCGI: header.type not handled: ", packet.type);
24566 buffer_free(packet.b);
24573 static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_host *host) {
24577 for (proc = host->first; proc; proc = proc->next) {
24580 if (p->conf.debug > 2) {
24581 - log_error_write(srv, __FILE__, __LINE__, "sbdddd",
24583 + log_error_write(srv, __FILE__, __LINE__, "sbdddd",
24585 proc->connection_name,
24595 * if the remote side is overloaded, we check back after <n> seconds
24599 switch (proc->state) {
24600 case PROC_STATE_KILLED:
24601 @@ -2592,13 +2511,13 @@
24603 case PROC_STATE_OVERLOADED:
24604 if (srv->cur_ts <= proc->disabled_until) break;
24607 proc->state = PROC_STATE_RUNNING;
24608 host->active_procs++;
24610 - log_error_write(srv, __FILE__, __LINE__, "sbdb",
24611 - "fcgi-server re-enabled:",
24612 - host->host, host->port,
24614 + log_error_write(srv, __FILE__, __LINE__, "sbdb",
24615 + "fcgi-server re-enabled:",
24616 + host->host, host->port,
24619 case PROC_STATE_DIED_WAIT_FOR_PID:
24620 @@ -2606,7 +2525,7 @@
24621 if (!proc->is_local) break;
24623 /* the child should not terminate at all */
24626 switch(waitpid(proc->pid, &status, WNOHANG)) {
24628 /* child is still alive */
24629 @@ -2616,45 +2535,45 @@
24631 if (WIFEXITED(status)) {
24633 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
24634 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
24635 "child exited, pid:", proc->pid,
24636 "status:", WEXITSTATUS(status));
24638 } else if (WIFSIGNALED(status)) {
24639 - log_error_write(srv, __FILE__, __LINE__, "sd",
24640 - "child signaled:",
24641 + log_error_write(srv, __FILE__, __LINE__, "sd",
24642 + "child signaled:",
24645 - log_error_write(srv, __FILE__, __LINE__, "sd",
24646 - "child died somehow:",
24647 + log_error_write(srv, __FILE__, __LINE__, "sd",
24648 + "child died somehow:",
24653 proc->state = PROC_STATE_DIED;
24658 /* fall through if we have a dead proc now */
24659 if (proc->state != PROC_STATE_DIED) break;
24661 case PROC_STATE_DIED:
24662 - /* local proc get restarted by us,
24663 + /* local proc get restarted by us,
24664 * remote ones hopefully by the admin */
24667 if (proc->is_local) {
24668 /* we still have connections bound to this proc,
24669 * let them terminate first */
24670 if (proc->load != 0) break;
24673 /* restart the child */
24676 if (p->conf.debug) {
24677 log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
24678 "--- fastcgi spawning",
24679 "\n\tsocket", proc->connection_name,
24680 "\n\tcurrent:", 1, "/", host->min_procs);
24684 if (fcgi_spawn_connection(srv, p, host, proc)) {
24685 log_error_write(srv, __FILE__, __LINE__, "s",
24686 "ERROR: spawning fcgi failed.");
24687 @@ -2662,18 +2581,18 @@
24690 if (srv->cur_ts <= proc->disabled_until) break;
24693 proc->state = PROC_STATE_RUNNING;
24694 host->active_procs++;
24696 - log_error_write(srv, __FILE__, __LINE__, "sb",
24697 - "fcgi-server re-enabled:",
24699 + log_error_write(srv, __FILE__, __LINE__, "sb",
24700 + "fcgi-server re-enabled:",
24701 proc->connection_name);
24711 @@ -2682,19 +2601,19 @@
24712 fcgi_extension_host *host= hctx->host;
24713 connection *con = hctx->remote_conn;
24719 - /* sanity check */
24720 + /* sanity check */
24722 ((!host->host->used || !host->port) && !host->unixsocket->used)) {
24723 - log_error_write(srv, __FILE__, __LINE__, "sxddd",
24724 + log_error_write(srv, __FILE__, __LINE__, "sxddd",
24725 "write-req: error",
24729 host->unixsocket->used);
24732 hctx->proc->disabled_until = srv->cur_ts + 10;
24733 hctx->proc->state = PROC_STATE_DIED;
24735 @@ -2705,12 +2624,12 @@
24736 if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
24738 socklen_t socket_error_len = sizeof(socket_error);
24741 /* try to finish the connect() */
24742 - if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
24743 - log_error_write(srv, __FILE__, __LINE__, "ss",
24744 + if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
24745 + log_error_write(srv, __FILE__, __LINE__, "ss",
24746 "getsockopt failed:", strerror(errno));
24749 hctx->proc->disabled_until = srv->cur_ts + 10;
24750 hctx->proc->state = PROC_STATE_DIED;
24752 @@ -2719,12 +2638,12 @@
24753 if (socket_error != 0) {
24754 if (!hctx->proc->is_local || p->conf.debug) {
24755 /* local procs get restarted */
24758 log_error_write(srv, __FILE__, __LINE__, "sssb",
24759 - "establishing connection failed:", strerror(socket_error),
24760 + "establishing connection failed:", strerror(socket_error),
24761 "socket:", hctx->proc->connection_name);
24765 hctx->proc->disabled_until = srv->cur_ts + 5;
24767 if (hctx->proc->is_local) {
24768 @@ -2732,17 +2651,17 @@
24770 hctx->proc->state = PROC_STATE_DIED;
24774 hctx->proc->state = PROC_STATE_DIED;
24777 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
24778 buffer_append_string(p->statuskey, ".died");
24780 status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
24783 return HANDLER_ERROR;
24785 - /* go on with preparing the request */
24786 + /* go on with preparing the request */
24787 hctx->state = FCGI_STATE_PREPARE_WRITE;
24790 @@ -2755,14 +2674,14 @@
24791 /* do we have a running process for this host (max-procs) ? */
24794 - for (proc = hctx->host->first;
24795 - proc && proc->state != PROC_STATE_RUNNING;
24796 + for (proc = hctx->host->first;
24797 + proc && proc->state != PROC_STATE_RUNNING;
24798 proc = proc->next);
24801 /* all childs are dead */
24802 if (proc == NULL) {
24803 - hctx->fde_ndx = -1;
24805 + hctx->sock->fde_ndx = -1;
24807 return HANDLER_ERROR;
24810 @@ -2775,50 +2694,50 @@
24813 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
24815 - if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
24817 + if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
24818 if (errno == EMFILE ||
24820 - log_error_write(srv, __FILE__, __LINE__, "sd",
24821 - "wait for fd at connection:", con->fd);
24823 + log_error_write(srv, __FILE__, __LINE__, "sd",
24824 + "wait for fd at connection:", con->sock->fd);
24826 return HANDLER_WAIT_FOR_FD;
24829 - log_error_write(srv, __FILE__, __LINE__, "ssdd",
24831 + log_error_write(srv, __FILE__, __LINE__, "ssdd",
24832 "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
24833 return HANDLER_ERROR;
24835 - hctx->fde_ndx = -1;
24837 + hctx->sock->fde_ndx = -1;
24841 - fdevent_register(srv->ev, hctx->fd, fcgi_handle_fdevent, hctx);
24843 - if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
24844 - log_error_write(srv, __FILE__, __LINE__, "ss",
24846 + fdevent_register(srv->ev, hctx->sock, fcgi_handle_fdevent, hctx);
24848 + if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
24849 + log_error_write(srv, __FILE__, __LINE__, "ss",
24850 "fcntl failed:", strerror(errno));
24853 return HANDLER_ERROR;
24857 if (hctx->proc->is_local) {
24858 hctx->pid = hctx->proc->pid;
24862 switch (fcgi_establish_connection(srv, hctx)) {
24863 case CONNECTION_DELAYED:
24864 /* connection is in progress, wait for an event and call getsockopt() below */
24866 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
24869 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
24871 fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT_DELAYED);
24872 return HANDLER_WAIT_FOR_EVENT;
24873 case CONNECTION_OVERLOADED:
24874 /* cool down the backend, it is overloaded
24877 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
24878 + log_error_write(srv, __FILE__, __LINE__, "ssdsd",
24879 "backend is overloaded, we disable it for a 2 seconds and send the request to another backend instead:",
24880 "reconnects:", hctx->reconnects,
24881 "load:", host->load);
24882 @@ -2831,7 +2750,7 @@
24883 buffer_append_string(p->statuskey, ".overloaded");
24885 status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
24888 return HANDLER_ERROR;
24889 case CONNECTION_DEAD:
24890 /* we got a hard error from the backend like
24891 @@ -2840,19 +2759,19 @@
24893 * for check if the host is back in 5 seconds
24897 hctx->proc->disabled_until = srv->cur_ts + 5;
24898 if (hctx->proc->is_local) {
24899 hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
24901 hctx->proc->state = PROC_STATE_DIED;
24904 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
24906 + log_error_write(srv, __FILE__, __LINE__, "ssdsd",
24907 "backend died, we disable it for a 5 seconds and send the request to another backend instead:",
24908 "reconnects:", hctx->reconnects,
24909 "load:", host->load);
24912 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
24913 buffer_append_string(p->statuskey, ".died");
24915 @@ -2863,19 +2782,19 @@
24916 /* everything is ok, go on */
24918 fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
24922 case CONNECTION_UNSET:
24927 case FCGI_STATE_PREPARE_WRITE:
24928 /* ok, we have the connection */
24931 hctx->proc->load++;
24932 hctx->proc->last_used = srv->cur_ts;
24933 hctx->got_proc = 1;
24936 status_counter_inc(srv, CONST_STR_LEN("fastcgi.requests"));
24937 status_counter_inc(srv, CONST_STR_LEN("fastcgi.active-requests"));
24939 @@ -2898,9 +2817,9 @@
24941 if (p->conf.debug) {
24942 log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
24944 - "pid:", hctx->proc->pid,
24945 - "socket:", hctx->proc->connection_name,
24947 + "pid:", hctx->proc->pid,
24948 + "socket:", hctx->proc->connection_name,
24949 "load:", hctx->proc->load);
24952 @@ -2908,74 +2827,75 @@
24953 if (hctx->request_id == 0) {
24954 hctx->request_id = fcgi_requestid_new(srv, p);
24956 - log_error_write(srv, __FILE__, __LINE__, "sd",
24957 + log_error_write(srv, __FILE__, __LINE__, "sd",
24958 "fcgi-request is already in use:", hctx->request_id);
24963 fcgi_create_env(srv, hctx, hctx->request_id);
24966 fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);
24970 case FCGI_STATE_WRITE:
24971 - ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
24972 + ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
24974 chunkqueue_remove_finished_chunks(hctx->wb);
24980 - /* the connection got dropped after accept()
24982 - * this is most of the time a PHP which dies
24983 + /* the connection got dropped after accept()
24985 + * this is most of the time a PHP which dies
24986 * after PHP_FCGI_MAX_REQUESTS
24991 if (hctx->wb->bytes_out == 0 &&
24992 hctx->reconnects < 5) {
24993 - usleep(10000); /* take away the load of the webserver
24994 - * to let the php a chance to restart
24996 + usleep(10000); /* take away the load of the webserver
24997 + * to let the php a chance to restart
25001 fcgi_reconnect(srv, hctx);
25004 return HANDLER_WAIT_FOR_FD;
25008 /* not reconnected ... why
25011 * far@#lighttpd report this for FreeBSD
25016 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
25018 + log_error_write(srv, __FILE__, __LINE__, "ssosd",
25019 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
25020 "write-offset:", hctx->wb->bytes_out,
25021 "reconnect attempts:", hctx->reconnects);
25024 return HANDLER_ERROR;
25027 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25029 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25031 return HANDLER_WAIT_FOR_EVENT;
25033 - log_error_write(srv, __FILE__, __LINE__, "ssd",
25034 + log_error_write(srv, __FILE__, __LINE__, "ssd",
25035 "write failed:", strerror(errno), errno);
25038 return HANDLER_ERROR;
25042 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
25043 /* we don't need the out event anymore */
25044 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
25045 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
25046 + fdevent_event_del(srv->ev, hctx->sock);
25047 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
25048 fcgi_set_state(srv, hctx, FCGI_STATE_READ);
25050 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25052 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25054 return HANDLER_WAIT_FOR_EVENT;
25057 @@ -2987,7 +2907,7 @@
25058 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
25059 return HANDLER_ERROR;
25063 return HANDLER_WAIT_FOR_EVENT;
25066 @@ -2996,18 +2916,18 @@
25068 SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
25069 plugin_data *p = p_d;
25072 handler_ctx *hctx = con->plugin_ctx[p->id];
25074 fcgi_extension_host *host;
25077 if (NULL == hctx) return HANDLER_GO_ON;
25081 if (con->mode != p->id) return HANDLER_GO_ON;
25083 /* we don't have a host yet, choose one
25084 - * -> this happens in the first round
25085 + * -> this happens in the first round
25086 * and when the host died and we have to select a new one */
25087 if (hctx->host == NULL) {
25089 @@ -3016,23 +2936,23 @@
25090 /* get best server */
25091 for (k = 0, ndx = -1; k < hctx->ext->used; k++) {
25092 host = hctx->ext->hosts[k];
25095 /* we should have at least one proc that can do something */
25096 if (host->active_procs == 0) continue;
25098 if (used == -1 || host->load < used) {
25107 /* found a server */
25109 /* all hosts are down */
25111 fcgi_connection_close(srv, hctx);
25114 con->http_status = 500;
25115 con->mode = DIRECT;
25117 @@ -3040,16 +2960,16 @@
25120 host = hctx->ext->hosts[ndx];
25123 - * if check-local is disabled, use the uri.path handler
25127 + * if check-local is disabled, use the uri.path handler
25132 /* init handler-context */
25135 - /* we put a connection on this host, move the other new connections to other hosts
25136 + /* we put a connection on this host, move the other new connections to other hosts
25138 * as soon as hctx->host is unassigned, decrease the load again */
25139 hctx->host->load++;
25140 @@ -3063,7 +2983,7 @@
25141 case HANDLER_ERROR:
25146 if (hctx->state == FCGI_STATE_INIT ||
25147 hctx->state == FCGI_STATE_CONNECT_DELAYED) {
25148 if (proc) host->active_procs--;
25149 @@ -3078,7 +2998,7 @@
25150 return HANDLER_WAIT_FOR_FD;
25152 fcgi_connection_close(srv, hctx);
25155 buffer_reset(con->physical.path);
25156 con->mode = DIRECT;
25157 con->http_status = 500;
25158 @@ -3088,12 +3008,12 @@
25161 fcgi_connection_close(srv, hctx);
25164 buffer_reset(con->physical.path);
25165 con->mode = DIRECT;
25166 con->http_status = 503;
25167 joblist_append(srv, con); /* really ? */
25170 return HANDLER_FINISHED;
25172 case HANDLER_WAIT_FOR_EVENT:
25173 @@ -3115,7 +3035,7 @@
25174 handler_ctx *hctx = ctx;
25175 connection *con = hctx->remote_conn;
25176 plugin_data *p = hctx->plugin_data;
25179 fcgi_proc *proc = hctx->proc;
25180 fcgi_extension_host *host= hctx->host;
25182 @@ -3125,8 +3045,8 @@
25187 - if (host->mode == FCGI_AUTHORIZER &&
25189 + if (host->mode == FCGI_AUTHORIZER &&
25190 (con->http_status == 200 ||
25191 con->http_status == 0)) {
25193 @@ -3136,26 +3056,26 @@
25196 buffer_copy_string_buffer(con->physical.doc_root, host->docroot);
25199 buffer_copy_string_buffer(con->physical.path, host->docroot);
25200 buffer_append_string_buffer(con->physical.path, con->uri.path);
25201 fcgi_connection_close(srv, hctx);
25204 con->mode = DIRECT;
25205 con->file_started = 1; /* fcgi_extension won't touch the request afterwards */
25208 fcgi_connection_close(srv, hctx);
25212 joblist_append(srv, con);
25213 return HANDLER_FINISHED;
25215 if (proc->pid && proc->state != PROC_STATE_DIED) {
25219 /* only fetch the zombie if it is not already done */
25222 switch(waitpid(proc->pid, &status, WNOHANG)) {
25224 /* child is still alive */
25225 @@ -3165,60 +3085,61 @@
25227 /* the child should not terminate at all */
25228 if (WIFEXITED(status)) {
25229 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
25230 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
25231 "child exited, pid:", proc->pid,
25232 "status:", WEXITSTATUS(status));
25233 } else if (WIFSIGNALED(status)) {
25234 - log_error_write(srv, __FILE__, __LINE__, "sd",
25235 - "child signaled:",
25236 + log_error_write(srv, __FILE__, __LINE__, "sd",
25237 + "child signaled:",
25240 - log_error_write(srv, __FILE__, __LINE__, "sd",
25241 - "child died somehow:",
25242 + log_error_write(srv, __FILE__, __LINE__, "sd",
25243 + "child died somehow:",
25248 if (p->conf.debug) {
25249 log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
25250 "--- fastcgi spawning",
25251 "\n\tsocket", proc->connection_name,
25252 "\n\tcurrent:", 1, "/", host->min_procs);
25256 if (fcgi_spawn_connection(srv, p, host, proc)) {
25257 /* respawning failed, retry later */
25258 proc->state = PROC_STATE_DIED;
25260 - log_error_write(srv, __FILE__, __LINE__, "s",
25261 + log_error_write(srv, __FILE__, __LINE__, "s",
25262 "respawning failed, will retry later");
25271 if (con->file_started == 0) {
25272 /* nothing has been send out yet, try to use another child */
25275 if (hctx->wb->bytes_out == 0 &&
25276 hctx->reconnects < 5) {
25277 fcgi_reconnect(srv, hctx);
25279 - log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25281 + log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25282 "response not received, request not sent",
25283 - "on socket:", proc->connection_name,
25284 + "on socket:", proc->connection_name,
25285 "for", con->uri.path, ", reconnecting");
25288 return HANDLER_WAIT_FOR_FD;
25291 - log_error_write(srv, __FILE__, __LINE__, "sosbsbs",
25293 + log_error_write(srv, __FILE__, __LINE__, "sosbsbs",
25294 "response not received, request sent:", hctx->wb->bytes_out,
25295 - "on socket:", proc->connection_name,
25296 + "on socket:", proc->connection_name,
25297 "for", con->uri.path, ", closing connection");
25300 fcgi_connection_close(srv, hctx);
25303 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
25304 buffer_reset(con->physical.path);
25305 con->http_status = 500;
25306 @@ -3226,76 +3147,76 @@
25308 /* response might have been already started, kill the connection */
25309 fcgi_connection_close(srv, hctx);
25311 - log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25313 + log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25314 "response already sent out, but backend returned error",
25315 - "on socket:", proc->connection_name,
25316 + "on socket:", proc->connection_name,
25317 "for", con->uri.path, ", terminating connection");
25320 connection_set_state(srv, con, CON_STATE_ERROR);
25328 joblist_append(srv, con);
25329 return HANDLER_FINISHED;
25334 if (revents & FDEVENT_OUT) {
25335 if (hctx->state == FCGI_STATE_CONNECT_DELAYED ||
25336 hctx->state == FCGI_STATE_WRITE) {
25337 /* we are allowed to send something out
25340 * 1. in a unfinished connect() call
25341 * 2. in a unfinished write() call (long POST request)
25343 return mod_fastcgi_handle_subrequest(srv, con, p);
25345 - log_error_write(srv, __FILE__, __LINE__, "sd",
25346 - "got a FDEVENT_OUT and didn't know why:",
25347 + log_error_write(srv, __FILE__, __LINE__, "sd",
25348 + "got a FDEVENT_OUT and didn't know why:",
25354 /* perhaps this issue is already handled */
25355 if (revents & FDEVENT_HUP) {
25356 if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
25357 /* getoptsock will catch this one (right ?)
25359 - * if we are in connect we might get a EINPROGRESS
25360 - * in the first call and a FDEVENT_HUP in the
25362 + * if we are in connect we might get a EINPROGRESS
25363 + * in the first call and a FDEVENT_HUP in the
25367 * FIXME: as it is a bit ugly.
25371 return mod_fastcgi_handle_subrequest(srv, con, p);
25372 } else if (hctx->state == FCGI_STATE_READ &&
25373 hctx->proc->port == 0) {
25377 * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
25378 * even if the FCGI_FIN packet is not received yet
25381 - log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
25382 - "error: unexpected close of fastcgi connection for",
25383 + log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
25384 + "error: unexpected close of fastcgi connection for",
25386 - "(no fastcgi process on host:",
25387 + "(no fastcgi process on host:",
25396 connection_set_state(srv, con, CON_STATE_ERROR);
25397 fcgi_connection_close(srv, hctx);
25398 joblist_append(srv, con);
25400 } else if (revents & FDEVENT_ERR) {
25401 - log_error_write(srv, __FILE__, __LINE__, "s",
25402 + log_error_write(srv, __FILE__, __LINE__, "s",
25403 "fcgi: got a FDEVENT_ERR. Don't know why.");
25404 /* kill all connections to the fastcgi process */
25406 @@ -3304,45 +3225,42 @@
25407 fcgi_connection_close(srv, hctx);
25408 joblist_append(srv, con);
25412 return HANDLER_FINISHED;
25414 -#define PATCH(x) \
25415 - p->conf.x = s->x;
25417 static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
25419 plugin_config *s = p->config_storage[0];
25423 - PATCH(ext_mapping);
25426 + PATCH_OPTION(exts);
25427 + PATCH_OPTION(debug);
25428 + PATCH_OPTION(ext_mapping);
25430 /* skip the first, the global context */
25431 for (i = 1; i < srv->config_context->used; i++) {
25432 data_config *dc = (data_config *)srv->config_context->data[i];
25433 s = p->config_storage[i];
25436 /* condition didn't match */
25437 if (!config_check_cond(srv, con, dc)) continue;
25441 for (j = 0; j < dc->value->used; j++) {
25442 data_unset *du = dc->value->data[j];
25445 if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.server"))) {
25447 + PATCH_OPTION(exts);
25448 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.debug"))) {
25450 + PATCH_OPTION(debug);
25451 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.map-extensions"))) {
25452 - PATCH(ext_mapping);
25453 + PATCH_OPTION(ext_mapping);
25464 static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
25465 plugin_data *p = p_d;
25466 @@ -3351,16 +3269,16 @@
25468 fcgi_extension *extension = NULL;
25469 fcgi_extension_host *host = NULL;
25472 /* Possibly, we processed already this request */
25473 if (con->file_started == 1) return HANDLER_GO_ON;
25475 fn = uri_path_handler ? con->uri.path : con->physical.path;
25477 if (buffer_is_empty(fn)) return HANDLER_GO_ON;
25480 s_len = fn->used - 1;
25483 fcgi_patch_connection(srv, con, p);
25485 /* fastcgi.map-extensions maps extensions to existing fastcgi.server entries
25486 @@ -3368,24 +3286,24 @@
25487 * fastcgi.map-extensions = ( ".php3" => ".php" )
25489 * fastcgi.server = ( ".php" => ... )
25494 /* check if extension-mapping matches */
25495 for (k = 0; k < p->conf.ext_mapping->used; k++) {
25496 data_string *ds = (data_string *)p->conf.ext_mapping->data[k];
25497 size_t ct_len; /* length of the config entry */
25500 if (ds->key->used == 0) continue;
25503 ct_len = ds->key->used - 1;
25506 if (s_len < ct_len) continue;
25509 /* found a mapping */
25510 if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
25511 /* check if we know the extension */
25514 /* we can reuse k here */
25515 for (k = 0; k < p->conf.exts->used; k++) {
25516 extension = p->conf.exts->exts[k];
25517 @@ -3407,15 +3325,15 @@
25518 /* check if extension matches */
25519 for (k = 0; k < p->conf.exts->used; k++) {
25520 size_t ct_len; /* length of the config entry */
25523 extension = p->conf.exts->exts[k];
25526 if (extension->key->used == 0) continue;
25529 ct_len = extension->key->used - 1;
25532 if (s_len < ct_len) continue;
25535 /* check extension in the form "/fcgi_pattern" */
25536 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
25538 @@ -3441,10 +3359,10 @@
25542 - /* we found one host that is alive */
25543 + /* we found one host that is alive */
25549 /* sorry, we don't have a server alive for this ext */
25550 buffer_reset(con->physical.path);
25551 @@ -3459,72 +3377,72 @@
25552 "on", extension->key,
25557 return HANDLER_FINISHED;
25560 /* a note about no handler is not sent yey */
25561 extension->note_is_sent = 0;
25564 - * if check-local is disabled, use the uri.path handler
25567 + * if check-local is disabled, use the uri.path handler
25572 /* init handler-context */
25573 if (uri_path_handler) {
25574 if (host->check_local == 0) {
25579 hctx = handler_ctx_init();
25582 hctx->remote_conn = con;
25583 hctx->plugin_data = p;
25585 hctx->ext = extension;
25589 hctx->conf.exts = p->conf.exts;
25590 hctx->conf.debug = p->conf.debug;
25593 con->plugin_ctx[p->id] = hctx;
25599 if (con->conf.log_request_handling) {
25600 - log_error_write(srv, __FILE__, __LINE__, "s",
25601 + log_error_write(srv, __FILE__, __LINE__, "s",
25602 "handling it in mod_fastcgi");
25605 - /* the prefix is the SCRIPT_NAME,
25607 + /* the prefix is the SCRIPT_NAME,
25608 * everthing from start to the next slash
25609 * this is important for check-local = "disable"
25612 * if prefix = /admin.fcgi
25615 * /admin.fcgi/foo/bar
25618 * SCRIPT_NAME = /admin.fcgi
25619 * PATH_INFO = /foo/bar
25622 * if prefix = /fcgi-bin/
25625 * /fcgi-bin/foo/bar
25628 * SCRIPT_NAME = /fcgi-bin/foo
25635 /* the rewrite is only done for /prefix/? matches */
25636 if (extension->key->ptr[0] == '/' &&
25637 con->uri.path->used > extension->key->used &&
25638 NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
25639 - /* rewrite uri.path and pathinfo */
25641 + /* rewrite uri.path and pathinfo */
25643 buffer_copy_string(con->request.pathinfo, pathinfo);
25646 con->uri.path->used -= con->request.pathinfo->used - 1;
25647 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
25649 @@ -3532,19 +3450,19 @@
25652 hctx = handler_ctx_init();
25655 hctx->remote_conn = con;
25656 hctx->plugin_data = p;
25658 hctx->ext = extension;
25661 hctx->conf.exts = p->conf.exts;
25662 hctx->conf.debug = p->conf.debug;
25665 con->plugin_ctx[p->id] = hctx;
25671 if (con->conf.log_request_handling) {
25672 log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
25674 @@ -3566,19 +3484,19 @@
25675 JOBLIST_FUNC(mod_fastcgi_handle_joblist) {
25676 plugin_data *p = p_d;
25677 handler_ctx *hctx = con->plugin_ctx[p->id];
25680 if (hctx == NULL) return HANDLER_GO_ON;
25682 - if (hctx->fd != -1) {
25683 + if (hctx->sock->fd != -1) {
25684 switch (hctx->state) {
25685 case FCGI_STATE_READ:
25686 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
25688 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
25691 case FCGI_STATE_CONNECT_DELAYED:
25692 case FCGI_STATE_WRITE:
25693 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25695 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25698 case FCGI_STATE_INIT:
25700 @@ -3595,7 +3513,7 @@
25702 static handler_t fcgi_connection_close_callback(server *srv, connection *con, void *p_d) {
25703 plugin_data *p = p_d;
25706 fcgi_connection_close(srv, con->plugin_ctx[p->id]);
25708 return HANDLER_GO_ON;
25709 @@ -3604,16 +3522,39 @@
25710 TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
25711 plugin_data *p = p_d;
25717 /* perhaps we should kill a connect attempt after 10-15 seconds
25720 * currently we wait for the TCP timeout which is on Linux 180 seconds
25727 + for (i = 0; i < srv->conns->used; i++) {
25728 + connection *con = srv->conns->ptr[i];
25729 + handler_ctx *hctx = con->plugin_ctx[p->id];
25731 + /* if a connection is ours and is in handle-req for more than max-request-time
25732 + * kill the connection */
25734 + if (con->mode != p->id) continue;
25735 + if (con->state != CON_STATE_HANDLE_REQUEST) continue;
25736 + if (srv->cur_ts < con->request_start + 60) continue;
25738 + /* the request is waiting for a FCGI_STDOUT since 60 seconds */
25740 + /* kill the connection */
25742 + log_error_write(srv, __FILE__, __LINE__, "s", "fastcgi backend didn't responded after 60 seconds");
25744 + fcgi_connection_close(srv, hctx);
25746 + con->mode = DIRECT;
25747 + con->http_status = 500;
25749 + joblist_append(srv, con);
25752 /* check all childs if they are still up */
25754 for (i = 0; i < srv->config_context->used; i++) {
25755 @@ -3628,45 +3569,45 @@
25756 fcgi_extension *ex;
25758 ex = exts->exts[j];
25761 for (n = 0; n < ex->used; n++) {
25765 unsigned long sum_load = 0;
25766 fcgi_extension_host *host;
25769 host = ex->hosts[n];
25772 fcgi_restart_dead_procs(srv, p, host);
25775 for (proc = host->first; proc; proc = proc->next) {
25776 sum_load += proc->load;
25780 if (host->num_procs &&
25781 host->num_procs < host->max_procs &&
25782 (sum_load / host->num_procs) > host->max_load_per_proc) {
25783 /* overload, spawn new child */
25784 if (p->conf.debug) {
25785 - log_error_write(srv, __FILE__, __LINE__, "s",
25786 + log_error_write(srv, __FILE__, __LINE__, "s",
25787 "overload detected, spawning a new child");
25791 for (proc = host->unused_procs; proc && proc->pid != 0; proc = proc->next);
25795 if (proc == host->unused_procs) host->unused_procs = proc->next;
25798 if (proc->next) proc->next->prev = NULL;
25803 proc = fastcgi_process_init();
25804 proc->id = host->max_id++;
25811 if (buffer_is_empty(host->unixsocket)) {
25812 proc->port = host->port + proc->id;
25814 @@ -3674,13 +3615,13 @@
25815 buffer_append_string(proc->unixsocket, "-");
25816 buffer_append_long(proc->unixsocket, proc->id);
25820 if (fcgi_spawn_connection(srv, p, host, proc)) {
25821 log_error_write(srv, __FILE__, __LINE__, "s",
25822 "ERROR: spawning fcgi failed.");
25823 return HANDLER_ERROR;
25828 proc->next = host->first;
25830 @@ -3688,56 +3629,56 @@
25832 host->first = proc;
25836 for (proc = host->first; proc; proc = proc->next) {
25837 if (proc->load != 0) break;
25838 if (host->num_procs <= host->min_procs) break;
25839 if (proc->pid == 0) continue;
25842 if (srv->cur_ts - proc->last_used > host->idle_timeout) {
25843 /* a proc is idling for a long time now,
25847 if (p->conf.debug) {
25848 - log_error_write(srv, __FILE__, __LINE__, "ssbsd",
25849 - "idle-timeout reached, terminating child:",
25850 - "socket:", proc->connection_name,
25851 + log_error_write(srv, __FILE__, __LINE__, "ssbsd",
25852 + "idle-timeout reached, terminating child:",
25853 + "socket:", proc->connection_name,
25860 if (proc->next) proc->next->prev = proc->prev;
25861 if (proc->prev) proc->prev->next = proc->next;
25864 if (proc->prev == NULL) host->first = proc->next;
25868 proc->next = host->unused_procs;
25871 if (host->unused_procs) host->unused_procs->prev = proc;
25872 host->unused_procs = proc;
25875 kill(proc->pid, SIGTERM);
25878 proc->state = PROC_STATE_KILLED;
25880 - log_error_write(srv, __FILE__, __LINE__, "ssbsd",
25882 - "socket:", proc->connection_name,
25884 + log_error_write(srv, __FILE__, __LINE__, "ssbsd",
25886 + "socket:", proc->connection_name,
25893 /* proc is now in unused, let the next second handle the next process */
25900 for (proc = host->unused_procs; proc; proc = proc->next) {
25904 if (proc->pid == 0) continue;
25907 switch (waitpid(proc->pid, &status, WNOHANG)) {
25909 /* child still running after timeout, good */
25910 @@ -3745,10 +3686,10 @@
25912 if (errno != EINTR) {
25913 /* no PID found ? should never happen */
25914 - log_error_write(srv, __FILE__, __LINE__, "sddss",
25915 + log_error_write(srv, __FILE__, __LINE__, "sddss",
25916 "pid ", proc->pid, proc->state,
25917 "not found:", strerror(errno));
25921 if (errno == ECHILD) {
25922 /* someone else has cleaned up for us */
25923 @@ -3762,25 +3703,26 @@
25924 /* the child should not terminate at all */
25925 if (WIFEXITED(status)) {
25926 if (proc->state != PROC_STATE_KILLED) {
25927 - log_error_write(srv, __FILE__, __LINE__, "sdb",
25929 + log_error_write(srv, __FILE__, __LINE__, "sdb",
25931 WEXITSTATUS(status), proc->connection_name);
25933 } else if (WIFSIGNALED(status)) {
25934 if (WTERMSIG(status) != SIGTERM) {
25935 - log_error_write(srv, __FILE__, __LINE__, "sd",
25936 - "child signaled:",
25937 + log_error_write(srv, __FILE__, __LINE__, "sd",
25938 + "child signaled:",
25942 - log_error_write(srv, __FILE__, __LINE__, "sd",
25943 - "child died somehow:",
25944 + log_error_write(srv, __FILE__, __LINE__, "sd",
25945 + "child died somehow:",
25949 proc->state = PROC_STATE_UNSET;
25956 @@ -3804,8 +3746,8 @@
25957 p->handle_subrequest = mod_fastcgi_handle_subrequest;
25958 p->handle_joblist = mod_fastcgi_handle_joblist;
25959 p->handle_trigger = mod_fastcgi_handle_trigger;
25967 --- ../lighttpd-1.4.11/src/mod_flv_streaming.c 2006-03-07 14:06:26.000000000 +0200
25968 +++ lighttpd-1.4.12/src/mod_flv_streaming.c 2006-07-16 00:26:04.000000000 +0300
25969 @@ -23,35 +23,35 @@
25979 plugin_config **config_storage;
25981 - plugin_config conf;
25983 + plugin_config conf;
25986 /* init the plugin data */
25987 INIT_FUNC(mod_flv_streaming_init) {
25991 p = calloc(1, sizeof(*p));
25994 p->query_str = buffer_init();
25995 p->get_params = array_init();
26001 /* detroy the plugin data */
26002 FREE_FUNC(mod_flv_streaming_free) {
26003 plugin_data *p = p_d;
26008 if (!p) return HANDLER_GO_ON;
26011 if (p->config_storage) {
26014 @@ -59,19 +59,19 @@
26015 plugin_config *s = p->config_storage[i];
26020 array_free(s->extensions);
26025 free(p->config_storage);
26029 buffer_free(p->query_str);
26030 array_free(p->get_params);
26036 return HANDLER_GO_ON;
26039 @@ -80,83 +80,80 @@
26040 SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) {
26041 plugin_data *p = p_d;
26044 - config_values_t cv[] = {
26046 + config_values_t cv[] = {
26047 { "flv-streaming.extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
26048 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26052 if (!p) return HANDLER_ERROR;
26055 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26058 for (i = 0; i < srv->config_context->used; i++) {
26062 s = calloc(1, sizeof(plugin_config));
26063 s->extensions = array_init();
26066 cv[0].destination = s->extensions;
26069 p->config_storage[i] = s;
26072 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
26073 return HANDLER_ERROR;
26078 return HANDLER_GO_ON;
26081 -#define PATCH(x) \
26082 - p->conf.x = s->x;
26083 static int mod_flv_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
26085 plugin_config *s = p->config_storage[0];
26087 - PATCH(extensions);
26090 + PATCH_OPTION(extensions);
26092 /* skip the first, the global context */
26093 for (i = 1; i < srv->config_context->used; i++) {
26094 data_config *dc = (data_config *)srv->config_context->data[i];
26095 s = p->config_storage[i];
26098 /* condition didn't match */
26099 if (!config_check_cond(srv, con, dc)) continue;
26103 for (j = 0; j < dc->value->used; j++) {
26104 data_unset *du = dc->value->data[j];
26107 if (buffer_is_equal_string(du->key, CONST_STR_LEN("flv-streaming.extensions"))) {
26108 - PATCH(extensions);
26109 + PATCH_OPTION(extensions);
26119 -static int split_get_params(server *srv, connection *con, array *get_params, buffer *qrystr) {
26120 +static int split_get_params(array *get_params, buffer *qrystr) {
26123 char *key = NULL, *val = NULL;
26129 /* we need the \0 */
26130 for (i = 0; i < qrystr->used; i++) {
26131 switch(qrystr->ptr[i]) {
26134 val = qrystr->ptr + i + 1;
26137 qrystr->ptr[i] = '\0';
26146 case '\0': /* fin symbol */
26147 @@ -167,7 +164,7 @@
26148 /* terminate the value */
26149 qrystr->ptr[i] = '\0';
26151 - if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
26152 + if (NULL == (ds = (data_string *)array_get_unused_element(get_params, TYPE_STRING))) {
26153 ds = data_string_init();
26155 buffer_copy_string_len(ds->key, key, strlen(key));
26156 @@ -175,14 +172,14 @@
26158 array_insert_unique(get_params, (data_unset *)ds);
26162 key = qrystr->ptr + i + 1;
26173 @@ -190,34 +187,34 @@
26174 plugin_data *p = p_d;
26181 if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
26184 mod_flv_streaming_patch_connection(srv, con, p);
26186 s_len = con->physical.path->used - 1;
26189 for (k = 0; k < p->conf.extensions->used; k++) {
26190 data_string *ds = (data_string *)p->conf.extensions->data[k];
26191 int ct_len = ds->value->used - 1;
26194 if (ct_len > s_len) continue;
26195 if (ds->value->used == 0) continue;
26198 if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
26199 data_string *get_param;
26200 stat_cache_entry *sce = NULL;
26204 - /* if there is a start=[0-9]+ in the header use it as start,
26205 + /* if there is a start=[0-9]+ in the header use it as start,
26206 * otherwise send the full file */
26208 array_reset(p->get_params);
26209 buffer_copy_string_buffer(p->query_str, con->uri.query);
26210 - split_get_params(srv, con, p->get_params, p->query_str);
26211 + split_get_params(p->get_params, p->query_str);
26213 if (NULL == (get_param = (data_string *)array_get_element(p->get_params, "start"))) {
26214 return HANDLER_GO_ON;
26215 @@ -256,7 +253,7 @@
26216 return HANDLER_FINISHED;
26222 return HANDLER_GO_ON;
26224 @@ -266,13 +263,13 @@
26225 int mod_flv_streaming_plugin_init(plugin *p) {
26226 p->version = LIGHTTPD_VERSION_ID;
26227 p->name = buffer_init_string("flv_streaming");
26230 p->init = mod_flv_streaming_init;
26231 p->handle_physical = mod_flv_streaming_path_handler;
26232 p->set_defaults = mod_flv_streaming_set_defaults;
26233 p->cleanup = mod_flv_streaming_free;
26241 --- ../lighttpd-1.4.11/src/mod_indexfile.c 2005-09-30 01:08:53.000000000 +0300
26242 +++ lighttpd-1.4.12/src/mod_indexfile.c 2006-07-16 00:26:04.000000000 +0300
26245 #include "stat_cache.h"
26247 +#include "sys-strings.h"
26248 +#include "sys-files.h"
26249 /* plugin config for all request/connections */
26252 @@ -20,51 +22,51 @@
26261 plugin_config **config_storage;
26263 - plugin_config conf;
26265 + plugin_config conf;
26268 /* init the plugin data */
26269 INIT_FUNC(mod_indexfile_init) {
26273 p = calloc(1, sizeof(*p));
26276 p->tmp_buf = buffer_init();
26282 /* detroy the plugin data */
26283 FREE_FUNC(mod_indexfile_free) {
26284 plugin_data *p = p_d;
26289 if (!p) return HANDLER_GO_ON;
26292 if (p->config_storage) {
26294 for (i = 0; i < srv->config_context->used; i++) {
26295 plugin_config *s = p->config_storage[i];
26300 array_free(s->indexfiles);
26305 free(p->config_storage);
26309 buffer_free(p->tmp_buf);
26315 return HANDLER_GO_ON;
26318 @@ -73,131 +75,139 @@
26319 SETDEFAULTS_FUNC(mod_indexfile_set_defaults) {
26320 plugin_data *p = p_d;
26323 - config_values_t cv[] = {
26325 + config_values_t cv[] = {
26326 { "index-file.names", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
26327 { "server.indexfiles", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
26328 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26332 if (!p) return HANDLER_ERROR;
26335 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26338 for (i = 0; i < srv->config_context->used; i++) {
26342 s = calloc(1, sizeof(plugin_config));
26343 s->indexfiles = array_init();
26346 cv[0].destination = s->indexfiles;
26347 cv[1].destination = s->indexfiles; /* old name for [0] */
26350 p->config_storage[i] = s;
26353 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
26354 return HANDLER_ERROR;
26359 return HANDLER_GO_ON;
26362 -#define PATCH(x) \
26363 - p->conf.x = s->x;
26364 static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_data *p) {
26366 plugin_config *s = p->config_storage[0];
26368 - PATCH(indexfiles);
26371 + PATCH_OPTION(indexfiles);
26373 /* skip the first, the global context */
26374 for (i = 1; i < srv->config_context->used; i++) {
26375 data_config *dc = (data_config *)srv->config_context->data[i];
26376 s = p->config_storage[i];
26379 /* condition didn't match */
26380 if (!config_check_cond(srv, con, dc)) continue;
26384 for (j = 0; j < dc->value->used; j++) {
26385 data_unset *du = dc->value->data[j];
26388 if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.indexfiles"))) {
26389 - PATCH(indexfiles);
26390 + PATCH_OPTION(indexfiles);
26391 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("index-file.names"))) {
26392 - PATCH(indexfiles);
26393 + PATCH_OPTION(indexfiles);
26403 URIHANDLER_FUNC(mod_indexfile_subrequest) {
26404 plugin_data *p = p_d;
26406 stat_cache_entry *sce = NULL;
26409 if (con->uri.path->used == 0) return HANDLER_GO_ON;
26410 if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
26413 mod_indexfile_patch_connection(srv, con, p);
26416 + /* is the physical-path really a dir ? */
26417 + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
26418 + return HANDLER_GO_ON;
26421 + if (!S_ISDIR(sce->st.st_mode)) {
26422 + return HANDLER_GO_ON;
26425 if (con->conf.log_request_handling) {
26426 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Indexfile");
26427 log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
26433 for (k = 0; k < p->conf.indexfiles->used; k++) {
26434 data_string *ds = (data_string *)p->conf.indexfiles->data[k];
26437 if (ds->value && ds->value->ptr[0] == '/') {
26438 - /* if the index-file starts with a prefix as use this file as
26439 + /* if the index-file starts with a prefix as use this file as
26440 * index-generator */
26441 buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
26443 buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
26444 + PATHNAME_APPEND_SLASH(p->tmp_buf);
26446 buffer_append_string_buffer(p->tmp_buf, ds->value);
26449 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
26450 if (errno == EACCES) {
26451 con->http_status = 403;
26452 buffer_reset(con->physical.path);
26455 return HANDLER_FINISHED;
26459 if (errno != ENOENT &&
26460 errno != ENOTDIR) {
26461 /* we have no idea what happend. let's tell the user so. */
26464 con->http_status = 500;
26467 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
26468 "file not found ... or so: ", strerror(errno),
26470 "->", con->physical.path);
26473 buffer_reset(con->physical.path);
26476 return HANDLER_FINISHED;
26482 /* rewrite uri.path to the real path (/ -> /index.php) */
26483 buffer_append_string_buffer(con->uri.path, ds->value);
26484 buffer_copy_string_buffer(con->physical.path, p->tmp_buf);
26487 /* fce is already set up a few lines above */
26490 return HANDLER_GO_ON;
26495 return HANDLER_GO_ON;
26497 @@ -207,13 +217,13 @@
26498 int mod_indexfile_plugin_init(plugin *p) {
26499 p->version = LIGHTTPD_VERSION_ID;
26500 p->name = buffer_init_string("indexfile");
26503 p->init = mod_indexfile_init;
26504 p->handle_subrequest_start = mod_indexfile_subrequest;
26505 p->set_defaults = mod_indexfile_set_defaults;
26506 p->cleanup = mod_indexfile_free;
26514 --- ../lighttpd-1.4.11/src/mod_mysql_vhost.c 2006-01-14 20:35:10.000000000 +0200
26515 +++ lighttpd-1.4.12/src/mod_mysql_vhost.c 2006-07-16 00:26:04.000000000 +0300
26517 -#include <unistd.h>
26521 -#include <strings.h>
26522 +#include <string.h>
26524 #ifdef HAVE_CONFIG_H
26525 #include "config.h"
26528 +#ifdef HAVE_MYSQL_H
26529 +# ifdef HAVE_LIBMYSQL
26530 +# define HAVE_MYSQL
26537 @@ -16,61 +21,40 @@
26540 #include "stat_cache.h"
26541 -#ifdef DEBUG_MOD_MYSQL_VHOST
26544 +#include "sys-files.h"
26547 - * Plugin for lighttpd to use MySQL
26548 - * for domain to directory lookups,
26549 - * i.e virtual hosts (vhosts).
26551 - * Optionally sets fcgi_offset and fcgi_arg
26552 - * in preparation for fcgi.c to handle
26553 - * per-user fcgi chroot jails.
26555 - * /ada@riksnet.se 2004-12-06
26557 +#include "mod_sql_vhost_core.h"
26561 +#define CORE_PLUGIN "mod_sql_vhost_core"
26571 - buffer *hostname;
26572 - unsigned short port;
26576 buffer *mysql_post;
26578 + mod_sql_vhost_core_plugin_config *core;
26581 /* global plugin data */
26589 plugin_config **config_storage;
26591 - plugin_config conf;
26593 + plugin_config conf;
26596 -/* per connection plugin data */
26598 - buffer *server_name;
26599 - buffer *document_root;
26600 - buffer *fcgi_arg;
26601 - unsigned fcgi_offset;
26602 -} plugin_connection_data;
26603 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost);
26605 /* init the plugin data */
26606 INIT_FUNC(mod_mysql_vhost_init) {
26610 p = calloc(1, sizeof(*p));
26612 p->tmp_buf = buffer_init();
26613 @@ -83,144 +67,77 @@
26614 plugin_data *p = p_d;
26619 - log_error_write(srv, __FILE__, __LINE__, "ss",
26620 - "mod_mysql_vhost_cleanup", p ? "yes" : "NO");
26623 if (!p) return HANDLER_GO_ON;
26626 if (p->config_storage) {
26628 for (i = 0; i < srv->config_context->used; i++) {
26629 plugin_config *s = p->config_storage[i];
26634 mysql_close(s->mysql);
26636 - buffer_free(s->mydb);
26637 - buffer_free(s->myuser);
26638 - buffer_free(s->mypass);
26639 - buffer_free(s->mysock);
26641 buffer_free(s->mysql_pre);
26642 buffer_free(s->mysql_post);
26647 free(p->config_storage);
26649 buffer_free(p->tmp_buf);
26653 - return HANDLER_GO_ON;
26656 -/* handle the plugin per connection data */
26657 -static void* mod_mysql_vhost_connection_data(server *srv, connection *con, void *p_d)
26659 - plugin_data *p = p_d;
26660 - plugin_connection_data *c = con->plugin_ctx[p->id];
26665 - log_error_write(srv, __FILE__, __LINE__, "ss",
26666 - "mod_mysql_connection_data", c ? "old" : "NEW");
26670 - c = calloc(1, sizeof(*c));
26672 - c->server_name = buffer_init();
26673 - c->document_root = buffer_init();
26674 - c->fcgi_arg = buffer_init();
26675 - c->fcgi_offset = 0;
26677 - return con->plugin_ctx[p->id] = c;
26680 -/* destroy the plugin per connection data */
26681 -CONNECTION_FUNC(mod_mysql_vhost_handle_connection_close) {
26682 - plugin_data *p = p_d;
26683 - plugin_connection_data *c = con->plugin_ctx[p->id];
26688 - log_error_write(srv, __FILE__, __LINE__, "ss",
26689 - "mod_mysql_vhost_handle_connection_close", c ? "yes" : "NO");
26692 - if (!c) return HANDLER_GO_ON;
26694 - buffer_free(c->server_name);
26695 - buffer_free(c->document_root);
26696 - buffer_free(c->fcgi_arg);
26697 - c->fcgi_offset = 0;
26702 - con->plugin_ctx[p->id] = NULL;
26703 return HANDLER_GO_ON;
26706 /* set configuration values */
26707 SERVER_FUNC(mod_mysql_vhost_set_defaults) {
26708 plugin_data *p = p_d;
26709 + mod_sql_vhost_core_plugin_data *core_config;
26714 - config_values_t cv[] = {
26715 - { "mysql-vhost.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
26716 - { "mysql-vhost.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
26717 - { "mysql-vhost.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
26718 - { "mysql-vhost.sock", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
26719 - { "mysql-vhost.sql", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
26720 - { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER },
26721 - { "mysql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER },
26722 - { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26725 + /* our very own plugin storage, one entry for each conditional
26727 + * srv->config_context->used is the number of conditionals
26729 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26732 + /* get the config of the core-plugin */
26733 + core_config = plugin_get_config(srv, CORE_PLUGIN);
26736 + /* walk through all conditionals and check for assignments */
26737 for (i = 0; i < srv->config_context->used; i++) {
26744 + /* get the config from the core plugin for this conditional-context */
26745 s = calloc(1, sizeof(plugin_config));
26746 - s->mydb = buffer_init();
26747 - s->myuser = buffer_init();
26748 - s->mypass = buffer_init();
26749 - s->mysock = buffer_init();
26750 - s->hostname = buffer_init();
26751 - s->port = 0; /* default port for mysql */
26752 - sel = buffer_init();
26755 + s->core = core_config->config_storage[i];
26759 s->mysql_pre = buffer_init();
26760 s->mysql_post = buffer_init();
26762 - cv[0].destination = s->mydb;
26763 - cv[1].destination = s->myuser;
26764 - cv[2].destination = s->mypass;
26765 - cv[3].destination = s->mysock;
26766 - cv[4].destination = sel;
26767 - cv[5].destination = s->hostname;
26768 - cv[6].destination = &(s->port);
26771 p->config_storage[i] = s;
26773 - if (config_insert_values_global(srv,
26774 - ((data_config *)srv->config_context->data[i])->value,
26775 - cv)) return HANDLER_ERROR;
26777 - s->mysql_pre = buffer_init();
26778 - s->mysql_post = buffer_init();
26781 + /* check if we are the plugin for this backend */
26782 + if (!buffer_is_equal_string(s->core->backend, CONST_STR_LEN("mysql"))) continue;
26784 + /* attach us to the core-plugin */
26785 + s->core->backend_data = p;
26786 + s->core->get_vhost = mod_mysql_vhost_get_vhost;
26788 + sel = buffer_init();
26789 + buffer_copy_string_buffer(sel, s->core->select_vhost);
26791 if (sel->used && (qmark = index(sel->ptr, '?'))) {
26793 buffer_copy_string(s->mysql_pre, sel->ptr);
26794 @@ -228,35 +145,35 @@
26796 buffer_copy_string_buffer(s->mysql_pre, sel);
26807 * - password, default: empty
26808 * - socket, default: mysql default
26809 * - hostname, if set overrides socket
26810 * - port, default: 3306
26814 /* all have to be set */
26815 - if (!(buffer_is_empty(s->myuser) ||
26816 - buffer_is_empty(s->mydb))) {
26817 + if (!(buffer_is_empty(s->core->user) ||
26818 + buffer_is_empty(s->core->db))) {
26823 if (NULL == (s->mysql = mysql_init(NULL))) {
26824 log_error_write(srv, __FILE__, __LINE__, "s", "mysql_init() failed, exiting...");
26827 return HANDLER_ERROR;
26829 -#define FOO(x) (s->x->used ? s->x->ptr : NULL)
26831 - if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass),
26832 - FOO(mydb), s->port, FOO(mysock), 0)) {
26833 +#define FOO(x) (s->core->x->used ? s->core->x->ptr : NULL)
26835 + if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(user), FOO(pass),
26836 + FOO(db), s->core->port, FOO(sock), 0)) {
26837 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(s->mysql));
26840 return HANDLER_ERROR;
26843 @@ -265,61 +182,47 @@
26844 /* otherwise we cannot be sure that mysql is fd i-1 */
26845 if (-1 == (fd = open("/dev/null", 0))) {
26847 - fcntl(fd-1, F_SETFD, FD_CLOEXEC);
26848 + fcntl(fd-1, F_SETFD, FD_CLOEXEC);
26857 return HANDLER_GO_ON;
26860 -#define PATCH(x) \
26861 - p->conf.x = s->x;
26862 static int mod_mysql_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
26865 plugin_config *s = p->config_storage[0];
26867 - PATCH(mysql_pre);
26868 - PATCH(mysql_post);
26874 + PATCH_OPTION(mysql_pre);
26875 + PATCH_OPTION(mysql_post);
26876 + PATCH_OPTION(mysql);
26878 /* skip the first, the global context */
26879 for (i = 1; i < srv->config_context->used; i++) {
26880 data_config *dc = (data_config *)srv->config_context->data[i];
26881 s = p->config_storage[i];
26884 /* condition didn't match */
26885 if (!config_check_cond(srv, con, dc)) continue;
26887 - /* merge config */
26888 - for (j = 0; j < dc->value->used; j++) {
26889 - data_unset *du = dc->value->data[j];
26891 - if (buffer_is_equal_string(du->key, CONST_STR_LEN("mysql-vhost.sql"))) {
26892 - PATCH(mysql_pre);
26893 - PATCH(mysql_post);
26900 + PATCH_OPTION(mysql);
26901 + PATCH_OPTION(mysql_pre);
26902 + PATCH_OPTION(mysql_post);
26912 -/* handle document root request */
26913 -CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
26915 + * get the vhost info from the database
26917 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost) {
26918 plugin_data *p = p_d;
26919 - plugin_connection_data *c;
26920 - stat_cache_entry *sce;
26924 @@ -332,13 +235,6 @@
26926 if (!p->conf.mysql) return HANDLER_GO_ON;
26928 - /* sets up connection data if not done yet */
26929 - c = mod_mysql_vhost_connection_data(srv, con, p_d);
26931 - /* check if cached this connection */
26932 - if (c->server_name->used && /* con->uri.authority->used && */
26933 - buffer_is_equal(c->server_name, con->uri.authority)) goto GO_ON;
26935 /* build and run SQL query */
26936 buffer_copy_string_buffer(p->tmp_buf, p->conf.mysql_pre);
26937 if (p->conf.mysql_post->used) {
26938 @@ -347,77 +243,43 @@
26940 if (mysql_query(p->conf.mysql, p->tmp_buf->ptr)) {
26941 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(p->conf.mysql));
26944 + mysql_free_result(result);
26945 + return HANDLER_GO_ON;
26947 result = mysql_store_result(p->conf.mysql);
26948 cols = mysql_num_fields(result);
26949 row = mysql_fetch_row(result);
26951 if (!row || cols < 1) {
26952 /* no such virtual host */
26953 mysql_free_result(result);
26954 return HANDLER_GO_ON;
26957 - /* sanity check that really is a directory */
26958 - buffer_copy_string(p->tmp_buf, row[0]);
26959 - BUFFER_APPEND_SLASH(p->tmp_buf);
26961 - if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
26962 - log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
26965 - if (!S_ISDIR(sce->st.st_mode)) {
26966 - log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->tmp_buf);
26969 + buffer_copy_string(docroot, row[0]);
26971 - /* cache the data */
26972 - buffer_copy_string_buffer(c->server_name, con->uri.authority);
26973 - buffer_copy_string_buffer(c->document_root, p->tmp_buf);
26975 - /* fcgi_offset and fcgi_arg are optional */
26976 - if (cols > 1 && row[1]) {
26977 - c->fcgi_offset = atoi(row[1]);
26979 - if (cols > 2 && row[2]) {
26980 - buffer_copy_string(c->fcgi_arg, row[2]);
26982 - c->fcgi_arg->used = 0;
26985 - c->fcgi_offset = c->fcgi_arg->used = 0;
26987 mysql_free_result(result);
26989 - /* fix virtual server and docroot */
26990 -GO_ON: buffer_copy_string_buffer(con->server_name, c->server_name);
26991 - buffer_copy_string_buffer(con->physical.doc_root, c->document_root);
26994 - log_error_write(srv, __FILE__, __LINE__, "sbbdb",
26995 - result ? "NOT CACHED" : "cached",
26996 - con->server_name, con->physical.doc_root,
26997 - c->fcgi_offset, c->fcgi_arg);
26999 - return HANDLER_GO_ON;
27001 -ERR500: if (result) mysql_free_result(result);
27002 - con->http_status = 500; /* Internal Error */
27003 - return HANDLER_FINISHED;
27004 + return HANDLER_GO_ON;
27007 /* this function is called at dlopen() time and inits the callbacks */
27008 int mod_mysql_vhost_plugin_init(plugin *p) {
27011 p->version = LIGHTTPD_VERSION_ID;
27012 p->name = buffer_init_string("mysql_vhost");
27014 p->init = mod_mysql_vhost_init;
27015 p->cleanup = mod_mysql_vhost_cleanup;
27016 - p->handle_request_done = mod_mysql_vhost_handle_connection_close;
27018 p->set_defaults = mod_mysql_vhost_set_defaults;
27019 - p->handle_docroot = mod_mysql_vhost_handle_docroot;
27021 + ds = data_string_init();
27022 + buffer_copy_string(ds->value, CORE_PLUGIN);
27023 + array_insert_unique(p->required_plugins, (data_unset *)ds);
27028 --- ../lighttpd-1.4.11/src/mod_proxy.c 2006-01-31 13:01:22.000000000 +0200
27029 +++ lighttpd-1.4.12/src/mod_proxy.c 2006-07-18 13:03:40.000000000 +0300
27031 #include <sys/types.h>
27033 -#include <unistd.h>
27036 #include <string.h>
27039 #include "inet_ntop_cache.h"
27041 +#include "network.h"
27043 +#include "http_resp.h"
27050 #include "sys-socket.h"
27051 +#include "sys-files.h"
27052 +#include "sys-strings.h"
27054 #define data_proxy data_fastcgi
27055 #define data_proxy_init data_fastcgi_init
27056 @@ -38,22 +42,25 @@
27057 #define PROXY_RETRY_TIMEOUT 60
27061 - * the proxy module is based on the fastcgi module
27064 + * the proxy module is based on the fastcgi module
27066 * 28.06.2004 Jan Kneschke The first release
27067 * 01.07.2004 Evgeny Rodichev Several bugfixes and cleanups
27068 * - co-ordinate up- and downstream flows correctly (proxy_demux_response
27069 * and proxy_handle_fdevent)
27070 * - correctly transfer upstream http_response_status;
27071 * - some unused structures removed.
27074 * TODO: - delay upstream read if write_queue is too large
27075 * (to prevent memory eating, like in apache). Shoud be
27077 * - persistent connection with upstream servers
27084 PROXY_BALANCE_UNSET,
27085 PROXY_BALANCE_FAIR,
27086 @@ -66,26 +73,33 @@
27089 proxy_balance_t balance;
27091 + array *last_used_backends; /* "extension" : last_used_backend */
27098 buffer *parse_response;
27099 buffer *balance_buf;
27104 + array *ignore_headers;
27106 plugin_config **config_storage;
27109 plugin_config conf;
27113 - PROXY_STATE_INIT,
27114 - PROXY_STATE_CONNECT,
27115 - PROXY_STATE_PREPARE_WRITE,
27116 - PROXY_STATE_WRITE,
27117 - PROXY_STATE_READ,
27118 - PROXY_STATE_ERROR
27120 + PROXY_STATE_INIT,
27121 + PROXY_STATE_CONNECT,
27122 + PROXY_STATE_PREPARE_WRITE,
27123 + PROXY_STATE_WRITE,
27124 + PROXY_STATE_RESPONSE_HEADER,
27125 + PROXY_STATE_RESPONSE_CONTENT,
27126 + PROXY_STATE_ERROR
27127 } proxy_connection_state_t;
27129 enum { PROXY_STDOUT, PROXY_END_REQUEST };
27130 @@ -93,19 +107,16 @@
27132 proxy_connection_state_t state;
27133 time_t state_timestamp;
27138 - buffer *response;
27139 - buffer *response_header;
27143 - int fd; /* fd to the proxy process */
27144 - int fde_ndx; /* index into the fd-event buffer */
27147 + iosocket *fd; /* fd to the proxy process */
27149 size_t path_info_offset; /* start of path_info in uri.path */
27152 connection *remote_conn; /* dump pointer */
27153 plugin_data *plugin_data; /* dump pointer */
27155 @@ -116,69 +127,89 @@
27157 static handler_ctx * handler_ctx_init() {
27158 handler_ctx * hctx;
27162 hctx = calloc(1, sizeof(*hctx));
27165 hctx->state = PROXY_STATE_INIT;
27168 - hctx->response = buffer_init();
27169 - hctx->response_header = buffer_init();
27171 hctx->wb = chunkqueue_init();
27172 + hctx->rb = chunkqueue_init();
27174 + hctx->fd = iosocket_init();
27177 - hctx->fde_ndx = -1;
27182 static void handler_ctx_free(handler_ctx *hctx) {
27183 - buffer_free(hctx->response);
27184 - buffer_free(hctx->response_header);
27185 chunkqueue_free(hctx->wb);
27187 + chunkqueue_free(hctx->rb);
27189 + iosocket_free(hctx->fd);
27194 INIT_FUNC(mod_proxy_init) {
27199 + char *hop2hop_headers[] = {
27206 p = calloc(1, sizeof(*p));
27208 - p->parse_response = buffer_init();
27210 p->balance_buf = buffer_init();
27212 + p->ignore_headers = array_init();
27213 + p->resp = http_response_init();
27215 + for (i = 0; hop2hop_headers[i]; i++) {
27218 + if (NULL == (ds = (data_string *)array_get_unused_element(p->ignore_headers, TYPE_STRING))) {
27219 + ds = data_string_init();
27222 + buffer_copy_string(ds->key, hop2hop_headers[i]);
27223 + buffer_copy_string(ds->value, hop2hop_headers[i]);
27224 + array_insert_unique(p->ignore_headers, (data_unset *)ds);
27231 FREE_FUNC(mod_proxy_free) {
27232 plugin_data *p = p_d;
27237 - buffer_free(p->parse_response);
27238 - buffer_free(p->balance_buf);
27240 if (p->config_storage) {
27242 for (i = 0; i < srv->config_context->used; i++) {
27243 plugin_config *s = p->config_storage[i];
27248 array_free(s->extensions);
27250 + array_free(s->last_used_backends);
27255 free(p->config_storage);
27259 + array_free(p->ignore_headers);
27260 + buffer_free(p->balance_buf);
27261 + http_response_free(p->resp);
27266 return HANDLER_GO_ON;
27269 @@ -186,37 +217,38 @@
27270 plugin_data *p = p_d;
27274 - config_values_t cv[] = {
27276 + config_values_t cv[] = {
27277 { "proxy.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
27278 { "proxy.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
27279 { "proxy.balance", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
27280 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
27284 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
27287 for (i = 0; i < srv->config_context->used; i++) {
27292 s = malloc(sizeof(plugin_config));
27293 - s->extensions = array_init();
27294 + s->extensions = array_init();
27295 + s->last_used_backends = array_init();
27299 cv[0].destination = s->extensions;
27300 cv[1].destination = &(s->debug);
27301 cv[2].destination = p->balance_buf;
27303 buffer_reset(p->balance_buf);
27306 p->config_storage[i] = s;
27307 ca = ((data_config *)srv->config_context->data[i])->value;
27310 if (0 != config_insert_values_global(srv, ca, cv)) {
27311 return HANDLER_ERROR;
27315 if (buffer_is_empty(p->balance_buf)) {
27316 s->balance = PROXY_BALANCE_FAIR;
27317 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) {
27318 @@ -226,99 +258,99 @@
27319 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("hash"))) {
27320 s->balance = PROXY_BALANCE_HASH;
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 + log_error_write(srv, __FILE__, __LINE__, "sb",
27325 + "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
27326 return HANDLER_ERROR;
27329 if (NULL != (du = array_get_element(ca, "proxy.server"))) {
27331 data_array *da = (data_array *)du;
27334 if (du->type != TYPE_ARRAY) {
27335 - log_error_write(srv, __FILE__, __LINE__, "sss",
27336 + log_error_write(srv, __FILE__, __LINE__, "sss",
27337 "unexpected type for key: ", "proxy.server", "array of strings");
27340 return HANDLER_ERROR;
27346 * proxy.server = ( "<ext>" => ...,
27351 for (j = 0; j < da->value->used; j++) {
27352 data_array *da_ext = (data_array *)da->value->data[j];
27356 if (da_ext->type != TYPE_ARRAY) {
27357 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
27358 - "unexpected type for key: ", "proxy.server",
27359 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
27360 + "unexpected type for key: ", "proxy.server",
27361 "[", da->value->data[j]->key, "](string)");
27364 return HANDLER_ERROR;
27368 - * proxy.server = ( "<ext>" =>
27369 - * ( "<host>" => ( ... ),
27372 + * proxy.server = ( "<ext>" =>
27373 + * ( "<host>" => ( ... ),
27374 * "<host>" => ( ... )
27381 for (n = 0; n < da_ext->value->used; n++) {
27382 data_array *da_host = (data_array *)da_ext->value->data[n];
27388 - config_values_t pcv[] = {
27390 + config_values_t pcv[] = {
27391 { "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
27392 { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
27393 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
27397 if (da_host->type != TYPE_ARRAY) {
27398 - log_error_write(srv, __FILE__, __LINE__, "ssSBS",
27399 - "unexpected type for key:",
27401 + log_error_write(srv, __FILE__, __LINE__, "ssSBS",
27402 + "unexpected type for key:",
27404 "[", da_ext->value->data[n]->key, "](string)");
27407 return HANDLER_ERROR;
27411 df = data_proxy_init();
27417 buffer_copy_string_buffer(df->key, da_host->key);
27420 pcv[0].destination = df->host;
27421 pcv[1].destination = &(df->port);
27424 if (0 != config_insert_values_internal(srv, da_host->value, pcv)) {
27425 return HANDLER_ERROR;
27429 if (buffer_is_empty(df->host)) {
27430 - log_error_write(srv, __FILE__, __LINE__, "sbbbs",
27431 - "missing key (string):",
27432 + log_error_write(srv, __FILE__, __LINE__, "sbbbs",
27433 + "missing key (string):",
27440 return HANDLER_ERROR;
27444 /* if extension already exists, take it */
27447 if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) {
27448 dfa = data_array_init();
27451 buffer_copy_string_buffer(dfa->key, da_ext->key);
27454 array_insert_unique(dfa->value, (data_unset *)df);
27455 array_insert_unique(s->extensions, (data_unset *)dfa);
27457 @@ -328,67 +360,76 @@
27463 return HANDLER_GO_ON;
27466 void proxy_connection_close(server *srv, handler_ctx *hctx) {
27471 if (NULL == hctx) return;
27474 p = hctx->plugin_data;
27475 con = hctx->remote_conn;
27478 if (hctx->fd != -1) {
27479 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
27480 + fdevent_event_del(srv->ev, hctx->fd);
27481 fdevent_unregister(srv->ev, hctx->fd);
27484 + close(hctx->fd->fd);
27489 handler_ctx_free(hctx);
27490 - con->plugin_ctx[p->id] = NULL;
27491 + con->plugin_ctx[p->id] = NULL;
27494 static int proxy_establish_connection(server *srv, handler_ctx *hctx) {
27495 struct sockaddr *proxy_addr;
27496 struct sockaddr_in proxy_addr_in;
27500 plugin_data *p = hctx->plugin_data;
27501 data_proxy *host= hctx->host;
27502 - int proxy_fd = hctx->fd;
27504 + int proxy_fd = hctx->fd->fd;
27506 memset(&proxy_addr, 0, sizeof(proxy_addr));
27509 proxy_addr_in.sin_family = AF_INET;
27510 proxy_addr_in.sin_addr.s_addr = inet_addr(host->host->ptr);
27511 proxy_addr_in.sin_port = htons(host->port);
27512 servlen = sizeof(proxy_addr_in);
27515 proxy_addr = (struct sockaddr *) &proxy_addr_in;
27518 if (-1 == connect(proxy_fd, proxy_addr, servlen)) {
27519 - if (errno == EINPROGRESS || errno == EALREADY) {
27521 + errno = WSAGetLastError();
27525 + case WSAEWOULDBLOCK:
27527 + case EINPROGRESS:
27529 if (p->conf.debug) {
27530 - log_error_write(srv, __FILE__, __LINE__, "sd",
27531 + log_error_write(srv, __FILE__, __LINE__, "sd",
27532 "connect delayed:", proxy_fd);
27539 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
27542 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
27543 "connect failed:", proxy_fd, strerror(errno), errno);
27549 + fprintf(stderr, "%s.%d: connected fd = %d\r\n", __FILE__, __LINE__, proxy_fd);
27550 if (p->conf.debug) {
27551 - log_error_write(srv, __FILE__, __LINE__, "sd",
27552 + log_error_write(srv, __FILE__, __LINE__, "sd",
27553 "connect succeeded: ", proxy_fd);
27556 @@ -396,51 +437,52 @@
27559 void proxy_set_header(connection *con, const char *key, const char *value) {
27560 - data_string *ds_dst;
27561 + data_string *ds_dst;
27563 - if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27564 - ds_dst = data_string_init();
27567 - buffer_copy_string(ds_dst->key, key);
27568 - buffer_copy_string(ds_dst->value, value);
27569 - array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27570 + if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27571 + ds_dst = data_string_init();
27574 + buffer_copy_string(ds_dst->key, key);
27575 + buffer_copy_string(ds_dst->value, value);
27576 + array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27579 void proxy_append_header(connection *con, const char *key, const char *value) {
27580 - data_string *ds_dst;
27581 + data_string *ds_dst;
27583 - if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27584 - ds_dst = data_string_init();
27587 - buffer_copy_string(ds_dst->key, key);
27588 - buffer_append_string(ds_dst->value, value);
27589 - array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27590 + if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27591 + ds_dst = data_string_init();
27594 + buffer_copy_string(ds_dst->key, key);
27595 + buffer_append_string(ds_dst->value, value);
27596 + array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27600 static int proxy_create_env(server *srv, handler_ctx *hctx) {
27604 connection *con = hctx->remote_conn;
27605 + plugin_data *p = hctx->plugin_data;
27611 b = chunkqueue_get_append_buffer(hctx->wb);
27615 buffer_copy_string(b, get_http_method_name(con->request.http_method));
27616 BUFFER_APPEND_STRING_CONST(b, " ");
27619 buffer_append_string_buffer(b, con->request.uri);
27620 BUFFER_APPEND_STRING_CONST(b, " HTTP/1.0\r\n");
27622 proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
27623 - /* http_host is NOT is just a pointer to a buffer
27624 + /* http_host is NOT is just a pointer to a buffer
27625 * which is NULL if it is not set */
27626 - if (con->request.http_host &&
27627 + if (con->request.http_host &&
27628 !buffer_is_empty(con->request.http_host)) {
27629 proxy_set_header(con, "X-Host", con->request.http_host->ptr);
27631 @@ -449,24 +491,25 @@
27632 /* request header */
27633 for (i = 0; i < con->request.headers->used; i++) {
27637 ds = (data_string *)con->request.headers->data[i];
27639 - if (ds->value->used && ds->key->used) {
27640 - if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
27642 - buffer_append_string_buffer(b, ds->key);
27643 - BUFFER_APPEND_STRING_CONST(b, ": ");
27644 - buffer_append_string_buffer(b, ds->value);
27645 - BUFFER_APPEND_STRING_CONST(b, "\r\n");
27648 + if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
27650 + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
27651 + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
27653 + buffer_append_string_buffer(b, ds->key);
27654 + BUFFER_APPEND_STRING_CONST(b, ": ");
27655 + buffer_append_string_buffer(b, ds->value);
27656 + BUFFER_APPEND_STRING_CONST(b, "\r\n");
27660 BUFFER_APPEND_STRING_CONST(b, "\r\n");
27663 hctx->wb->bytes_in += b->used - 1;
27667 if (con->request.content_length) {
27668 chunkqueue *req_cq = con->request_content_queue;
27670 @@ -479,7 +522,7 @@
27672 /* we announce toWrite octects
27673 * now take all the request_content chunk that we need to fill this request
27677 switch (req_c->type) {
27679 @@ -507,223 +550,150 @@
27681 req_c->offset += weHave;
27682 req_cq->bytes_out += weHave;
27685 hctx->wb->bytes_in += weHave;
27702 static int proxy_set_state(server *srv, handler_ctx *hctx, proxy_connection_state_t state) {
27703 hctx->state = state;
27704 hctx->state_timestamp = srv->cur_ts;
27710 -static int proxy_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
27712 - int http_response_status = -1;
27716 - /* \r\n -> \0\0 */
27718 - buffer_copy_string_buffer(p->parse_response, in);
27720 - for (s = p->parse_response->ptr; NULL != (ns = strstr(s, "\r\n")); s = ns + 2) {
27721 - char *key, *value;
27729 - if (-1 == http_response_status) {
27730 - /* The first line of a Response message is the Status-Line */
27732 - for (key=s; *key && *key != ' '; key++);
27735 - http_response_status = (int) strtol(key, NULL, 10);
27736 - if (http_response_status <= 0) http_response_status = 502;
27738 - http_response_status = 502;
27741 - con->http_status = http_response_status;
27742 - con->parsed_response |= HTTP_STATUS;
27746 - if (NULL == (value = strchr(s, ':'))) {
27747 - /* now we expect: "<key>: <value>\n" */
27753 - key_len = value - key;
27757 - while (*value == ' ' || *value == '\t') value++;
27761 - switch(key_len) {
27763 - if (0 == strncasecmp(key, "Date", key_len)) {
27764 - con->parsed_response |= HTTP_DATE;
27768 - if (0 == strncasecmp(key, "Location", key_len)) {
27769 - con->parsed_response |= HTTP_LOCATION;
27773 - if (0 == strncasecmp(key, "Connection", key_len)) {
27778 - if (0 == strncasecmp(key, "Content-Length", key_len)) {
27779 - con->response.content_length = strtol(value, NULL, 10);
27780 - con->parsed_response |= HTTP_CONTENT_LENGTH;
27787 - if (copy_header) {
27788 - if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
27789 - ds = data_response_init();
27791 - buffer_copy_string_len(ds->key, key, key_len);
27792 - buffer_copy_string(ds->value, value);
27794 - array_insert_unique(con->response.headers, (data_unset *)ds);
27802 static int proxy_demux_response(server *srv, handler_ctx *hctx) {
27807 plugin_data *p = hctx->plugin_data;
27808 connection *con = hctx->remote_conn;
27809 - int proxy_fd = hctx->fd;
27811 - /* check how much we have to read */
27812 - if (ioctl(hctx->fd, FIONREAD, &b)) {
27813 - log_error_write(srv, __FILE__, __LINE__, "sd",
27814 - "ioctl failed: ",
27816 + chunkqueue *next_queue = NULL;
27819 + switch(srv->network_backend_read(srv, con, hctx->fd, hctx->rb)) {
27820 + case NETWORK_STATUS_SUCCESS:
27821 + /* we got content */
27823 + case NETWORK_STATUS_WAIT_FOR_EVENT:
27825 + case NETWORK_STATUS_CONNECTION_CLOSE:
27826 + /* we are done, get out of here */
27827 + con->file_finished = 1;
27829 + /* close the chunk-queue with a empty chunk */
27837 + /* looks like we got some content
27839 + * split off the header from the incoming stream
27842 - if (p->conf.debug) {
27843 - log_error_write(srv, __FILE__, __LINE__, "sd",
27844 - "proxy - have to read:", b);
27846 + if (hctx->state == PROXY_STATE_RESPONSE_HEADER) {
27848 + int have_content_length = 0;
27851 - if (hctx->response->used == 0) {
27852 - /* avoid too small buffer */
27853 - buffer_prepare_append(hctx->response, b + 1);
27854 - hctx->response->used = 1;
27856 - buffer_prepare_append(hctx->response, hctx->response->used + b);
27859 - if (-1 == (r = read(hctx->fd, hctx->response->ptr + hctx->response->used - 1, b))) {
27860 - log_error_write(srv, __FILE__, __LINE__, "sds",
27861 - "unexpected end-of-file (perhaps the proxy process died):",
27862 - proxy_fd, strerror(errno));
27866 - /* this should be catched by the b > 0 above */
27869 - hctx->response->used += r;
27870 - hctx->response->ptr[hctx->response->used - 1] = '\0';
27873 - log_error_write(srv, __FILE__, __LINE__, "sdsbs",
27874 - "demux: Response buffer len", hctx->response->used, ":", hctx->response, ":");
27876 + http_response_reset(p->resp);
27878 - if (0 == con->got_response) {
27879 - con->got_response = 1;
27880 - buffer_prepare_copy(hctx->response_header, 128);
27883 - if (0 == con->file_started) {
27886 - /* search for the \r\n\r\n in the string */
27887 - if (NULL != (c = buffer_search_string_len(hctx->response, "\r\n\r\n", 4))) {
27888 - size_t hlen = c - hctx->response->ptr + 4;
27889 - size_t blen = hctx->response->used - hlen - 1;
27892 - buffer_append_string_len(hctx->response_header, hctx->response->ptr, c - hctx->response->ptr + 4);
27894 - log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header);
27896 - /* parse the response header */
27897 - proxy_response_parse(srv, con, p, hctx->response_header);
27899 - /* enable chunked-transfer-encoding */
27900 - if (con->request.http_version == HTTP_VERSION_1_1 &&
27901 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
27902 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
27903 + /* the response header is not fully received yet,
27905 + * extract the http-response header from the rb-cq
27907 + switch (http_response_parse_cq(hctx->rb, p->resp)) {
27908 + case PARSE_ERROR:
27909 + /* parsing failed */
27911 + con->http_status = 502; /* Bad Gateway */
27913 + case PARSE_NEED_MORE:
27915 + case PARSE_SUCCESS:
27916 + con->http_status = p->resp->status;
27918 + chunkqueue_remove_finished_chunks(hctx->rb);
27920 + /* copy the http-headers */
27921 + for (i = 0; i < p->resp->headers->used; i++) {
27922 + const char *ign[] = { "Status", "Connection", NULL };
27926 + data_string *header = (data_string *)p->resp->headers->data[i];
27928 + /* some headers are ignored by default */
27929 + for (j = 0; ign[j]; j++) {
27930 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
27932 + if (ign[j]) continue;
27934 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
27935 + /* CGI/1.1 rev 03 - 7.2.1.2 */
27936 + if (con->http_status == 0) con->http_status = 302;
27937 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
27938 + have_content_length = 1;
27941 - con->file_started = 1;
27943 - http_chunk_append_mem(srv, con, c + 4, blen + 1);
27944 - joblist_append(srv, con);
27946 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
27947 + ds = data_response_init();
27949 - hctx->response->used = 0;
27950 + buffer_copy_string_buffer(ds->key, header->key);
27951 + buffer_copy_string_buffer(ds->value, header->value);
27953 + array_insert_unique(con->response.headers, (data_unset *)ds);
27956 - http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
27957 - joblist_append(srv, con);
27958 - hctx->response->used = 0;
27960 + con->file_started = 1;
27962 + if (con->request.http_version == HTTP_VERSION_1_1 &&
27963 + !have_content_length) {
27964 + con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
27967 + hctx->state = PROXY_STATE_RESPONSE_CONTENT;
27972 - /* reading from upstream done */
27973 - con->file_finished = 1;
27975 - http_chunk_append_mem(srv, con, NULL, 0);
27976 - joblist_append(srv, con);
27983 + /* FIXME: pass the response-header to the other plugins to
27984 + * setup the filter-queue
27986 + * - use next-queue instead of con->write_queue
27989 + next_queue = con->write_queue;
27991 + assert(hctx->state == PROXY_STATE_RESPONSE_CONTENT);
27993 + /* FIXME: if we have a content-length or chunked-encoding
27996 + * for now we wait for EOF on the socket */
27998 + /* copy the content to the next cq */
27999 + for (c = hctx->rb->first; c; c = c->next) {
28000 + http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
28002 + c->offset = c->mem->used - 1;
28005 + chunkqueue_remove_finished_chunks(hctx->rb);
28006 + joblist_append(srv, con);
28012 @@ -731,32 +701,32 @@
28013 data_proxy *host= hctx->host;
28014 plugin_data *p = hctx->plugin_data;
28015 connection *con = hctx->remote_conn;
28021 - (!host->host->used || !host->port)) return -1;
28025 + (!host->host->used || !host->port)) return -1;
28027 switch(hctx->state) {
28028 case PROXY_STATE_INIT:
28029 - if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
28030 + if (-1 == (hctx->fd->fd = socket(AF_INET, SOCK_STREAM, 0))) {
28031 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
28032 return HANDLER_ERROR;
28034 - hctx->fde_ndx = -1;
28036 + hctx->fd->fde_ndx = -1;
28041 fdevent_register(srv->ev, hctx->fd, proxy_handle_fdevent, hctx);
28044 if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
28045 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
28048 return HANDLER_ERROR;
28055 case PROXY_STATE_CONNECT:
28056 /* try to finish the connect() */
28057 if (hctx->state == PROXY_STATE_INIT) {
28058 @@ -764,16 +734,16 @@
28059 switch (proxy_establish_connection(srv, hctx)) {
28061 proxy_set_state(srv, hctx, PROXY_STATE_CONNECT);
28064 /* connection is in progress, wait for an event and call getsockopt() below */
28066 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28069 + fdevent_event_add(srv->ev, hctx->fd, FDEVENT_OUT);
28071 return HANDLER_WAIT_FOR_EVENT;
28073 /* if ECONNREFUSED choose another connection -> FIXME */
28074 - hctx->fde_ndx = -1;
28076 + hctx->fd->fde_ndx = -1;
28078 return HANDLER_ERROR;
28080 /* everything is ok, go on */
28081 @@ -782,152 +752,152 @@
28084 socklen_t socket_error_len = sizeof(socket_error);
28086 - /* we don't need it anymore */
28087 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
28089 + /* we don't need it anymore */
28090 + fdevent_event_del(srv->ev, hctx->fd);
28092 /* try to finish the connect() */
28093 - if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28094 - log_error_write(srv, __FILE__, __LINE__, "ss",
28095 + if (0 != getsockopt(hctx->fd->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28096 + log_error_write(srv, __FILE__, __LINE__, "ss",
28097 "getsockopt failed:", strerror(errno));
28100 return HANDLER_ERROR;
28102 if (socket_error != 0) {
28103 log_error_write(srv, __FILE__, __LINE__, "ss",
28104 - "establishing connection failed:", strerror(socket_error),
28105 + "establishing connection failed:", strerror(socket_error),
28106 "port:", hctx->host->port);
28109 return HANDLER_ERROR;
28111 if (p->conf.debug) {
28112 - log_error_write(srv, __FILE__, __LINE__, "s", "proxy - connect - delayed success");
28113 + log_error_write(srv, __FILE__, __LINE__, "s", "proxy - connect - delayed success");
28118 proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);
28120 case PROXY_STATE_PREPARE_WRITE:
28121 proxy_create_env(srv, hctx);
28124 proxy_set_state(srv, hctx, PROXY_STATE_WRITE);
28128 case PROXY_STATE_WRITE:;
28129 - ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
28130 + ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
28132 chunkqueue_remove_finished_chunks(hctx->wb);
28135 - if (errno != EAGAIN &&
28136 - errno != EINTR) {
28137 - log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
28139 - return HANDLER_ERROR;
28141 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28143 + case NETWORK_STATUS_FATAL_ERROR:
28144 + log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
28146 - return HANDLER_WAIT_FOR_EVENT;
28148 + return HANDLER_ERROR;
28149 + case NETWORK_STATUS_WAIT_FOR_EVENT:
28151 + fdevent_event_add(srv->ev, hctx->fd, FDEVENT_OUT);
28153 + return HANDLER_WAIT_FOR_EVENT;
28156 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
28157 - proxy_set_state(srv, hctx, PROXY_STATE_READ);
28158 + proxy_set_state(srv, hctx, PROXY_STATE_RESPONSE_HEADER);
28160 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
28161 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
28162 + fdevent_event_del(srv->ev, hctx->fd);
28163 + fdevent_event_add(srv->ev, hctx->fd, FDEVENT_IN);
28165 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28167 + fdevent_event_add(srv->ev, hctx->fd, FDEVENT_OUT);
28169 return HANDLER_WAIT_FOR_EVENT;
28173 return HANDLER_WAIT_FOR_EVENT;
28174 - case PROXY_STATE_READ:
28175 + case PROXY_STATE_RESPONSE_CONTENT:
28176 + case PROXY_STATE_RESPONSE_HEADER:
28177 /* waiting for a response */
28179 return HANDLER_WAIT_FOR_EVENT;
28181 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
28182 return HANDLER_ERROR;
28186 return HANDLER_GO_ON;
28189 -#define PATCH(x) \
28190 - p->conf.x = s->x;
28191 static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data *p) {
28193 plugin_config *s = p->config_storage[0];
28195 - PATCH(extensions);
28200 + PATCH_OPTION(extensions);
28201 + PATCH_OPTION(debug);
28202 + PATCH_OPTION(balance);
28203 + PATCH_OPTION(last_used_backends);
28205 /* skip the first, the global context */
28206 for (i = 1; i < srv->config_context->used; i++) {
28207 data_config *dc = (data_config *)srv->config_context->data[i];
28208 s = p->config_storage[i];
28211 /* condition didn't match */
28212 if (!config_check_cond(srv, con, dc)) continue;
28216 for (j = 0; j < dc->value->used; j++) {
28217 data_unset *du = dc->value->data[j];
28220 if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.server"))) {
28221 - PATCH(extensions);
28222 + PATCH_OPTION(extensions);
28223 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.debug"))) {
28225 + PATCH_OPTION(debug);
28226 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.balance"))) {
28228 + PATCH_OPTION(balance);
28229 + PATCH_OPTION(last_used_backends);
28239 SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
28240 plugin_data *p = p_d;
28243 handler_ctx *hctx = con->plugin_ctx[p->id];
28247 if (NULL == hctx) return HANDLER_GO_ON;
28249 mod_proxy_patch_connection(srv, con, p);
28256 if (con->mode != p->id) return HANDLER_GO_ON;
28259 /* ok, create the request */
28260 switch(proxy_write_request(srv, hctx)) {
28261 case HANDLER_ERROR:
28262 - log_error_write(srv, __FILE__, __LINE__, "sbdd", "proxy-server disabled:",
28263 + log_error_write(srv, __FILE__, __LINE__, "sbdd", "proxy-server disabled:",
28270 /* disable this server */
28271 host->is_disabled = 1;
28272 host->disable_ts = srv->cur_ts;
28275 proxy_connection_close(srv, hctx);
28277 - /* reset the enviroment and restart the sub-request */
28279 + /* reset the enviroment and restart the sub-request */
28280 buffer_reset(con->physical.path);
28281 con->mode = DIRECT;
28283 joblist_append(srv, con);
28285 - /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
28286 - * and hope that the childs will be restarted
28288 + /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
28289 + * and hope that the childs will be restarted
28293 return HANDLER_WAIT_FOR_FD;
28294 @@ -938,7 +908,7 @@
28300 if (con->file_started == 1) {
28301 return HANDLER_FINISHED;
28303 @@ -951,13 +921,14 @@
28304 handler_ctx *hctx = ctx;
28305 connection *con = hctx->remote_conn;
28306 plugin_data *p = hctx->plugin_data;
28311 if ((revents & FDEVENT_IN) &&
28312 - hctx->state == PROXY_STATE_READ) {
28313 + (hctx->state == PROXY_STATE_RESPONSE_HEADER ||
28314 + hctx->state == PROXY_STATE_RESPONSE_CONTENT)) {
28316 if (p->conf.debug) {
28317 - log_error_write(srv, __FILE__, __LINE__, "sd",
28318 + log_error_write(srv, __FILE__, __LINE__, "sd",
28319 "proxy: fdevent-in", hctx->state);
28322 @@ -965,11 +936,15 @@
28326 + log_error_write(srv, __FILE__, __LINE__, "sd",
28327 + "proxy: request done", hctx->fd->fd);
28328 hctx->host->usage--;
28331 + http_chunk_append_mem(srv, con, NULL, 0);
28334 proxy_connection_close(srv, hctx);
28337 joblist_append(srv, con);
28338 return HANDLER_FINISHED;
28340 @@ -982,53 +957,53 @@
28341 /* response might have been already started, kill the connection */
28342 connection_set_state(srv, con, CON_STATE_ERROR);
28346 joblist_append(srv, con);
28347 return HANDLER_FINISHED;
28352 if (revents & FDEVENT_OUT) {
28353 if (p->conf.debug) {
28354 - log_error_write(srv, __FILE__, __LINE__, "sd",
28355 + log_error_write(srv, __FILE__, __LINE__, "sd",
28356 "proxy: fdevent-out", hctx->state);
28359 if (hctx->state == PROXY_STATE_CONNECT ||
28360 hctx->state == PROXY_STATE_WRITE) {
28361 /* we are allowed to send something out
28364 * 1. in a unfinished connect() call
28365 * 2. in a unfinished write() call (long POST request)
28367 return mod_proxy_handle_subrequest(srv, con, p);
28369 - log_error_write(srv, __FILE__, __LINE__, "sd",
28370 + log_error_write(srv, __FILE__, __LINE__, "sd",
28371 "proxy: out", hctx->state);
28376 /* perhaps this issue is already handled */
28377 if (revents & FDEVENT_HUP) {
28378 if (p->conf.debug) {
28379 - log_error_write(srv, __FILE__, __LINE__, "sd",
28380 + log_error_write(srv, __FILE__, __LINE__, "sd",
28381 "proxy: fdevent-hup", hctx->state);
28385 if (hctx->state == PROXY_STATE_CONNECT) {
28386 /* connect() -> EINPROGRESS -> HUP */
28390 - * what is proxy is doing if it can't reach the next hop ?
28392 + * what is proxy is doing if it can't reach the next hop ?
28397 proxy_connection_close(srv, hctx);
28398 joblist_append(srv, con);
28401 con->http_status = 503;
28402 con->mode = DIRECT;
28405 return HANDLER_FINISHED;
28408 @@ -1038,13 +1013,13 @@
28409 joblist_append(srv, con);
28410 } else if (revents & FDEVENT_ERR) {
28411 /* kill all connections to the proxy process */
28414 log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents);
28416 joblist_append(srv, con);
28417 proxy_connection_close(srv, hctx);
28421 return HANDLER_FINISHED;
28424 @@ -1058,44 +1033,48 @@
28426 data_array *extension = NULL;
28427 size_t path_info_offset;
28429 + data_integer *last_used_backend;
28430 + data_proxy *host = NULL;
28431 + handler_ctx *hctx = NULL;
28433 + array *backends = NULL;
28435 /* Possibly, we processed already this request */
28436 if (con->file_started == 1) return HANDLER_GO_ON;
28439 mod_proxy_patch_connection(srv, con, p);
28442 fn = con->uri.path;
28444 if (fn->used == 0) {
28445 return HANDLER_ERROR;
28449 s_len = fn->used - 1;
28453 path_info_offset = 0;
28455 - if (p->conf.debug) {
28456 + if (p->conf.debug) {
28457 log_error_write(srv, __FILE__, __LINE__, "s", "proxy - start");
28460 /* check if extension matches */
28461 for (k = 0; k < p->conf.extensions->used; k++) {
28465 extension = (data_array *)p->conf.extensions->data[k];
28468 if (extension->key->used == 0) continue;
28471 ct_len = extension->key->used - 1;
28474 if (s_len < ct_len) continue;
28477 /* check extension in the form "/proxy_pattern" */
28478 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
28479 if (s_len > ct_len + 1) {
28483 if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) {
28484 path_info_offset = pi_offset - fn->ptr;
28486 @@ -1106,12 +1085,14 @@
28492 if (k == p->conf.extensions->used) {
28493 return HANDLER_GO_ON;
28496 - if (p->conf.debug) {
28497 + backends = extension->value;
28499 + if (p->conf.debug) {
28500 log_error_write(srv, __FILE__, __LINE__, "s", "proxy - ext found");
28503 @@ -1120,34 +1101,34 @@
28504 /* hash balancing */
28506 if (p->conf.debug) {
28507 - log_error_write(srv, __FILE__, __LINE__, "sd",
28508 - "proxy - used hash balancing, hosts:", extension->value->used);
28509 + log_error_write(srv, __FILE__, __LINE__, "sd",
28510 + "proxy - used hash balancing, hosts:", backends->used);
28513 - for (k = 0, ndx = -1, last_max = ULONG_MAX; k < extension->value->used; k++) {
28514 - data_proxy *host = (data_proxy *)extension->value->data[k];
28515 + for (k = 0, ndx = -1, last_max = ULONG_MAX; k < backends->used; k++) {
28516 unsigned long cur_max;
28518 - if (host->is_disabled) continue;
28520 + data_proxy *cur = (data_proxy *)backends->data[k];
28522 + if (cur->is_disabled) continue;
28524 cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
28525 - generate_crc32c(CONST_BUF_LEN(host->host)) + /* we can cache this */
28526 + generate_crc32c(CONST_BUF_LEN(cur->host)) + /* we can cache this */
28527 generate_crc32c(CONST_BUF_LEN(con->uri.authority));
28530 if (p->conf.debug) {
28531 - log_error_write(srv, __FILE__, __LINE__, "sbbbd",
28532 + log_error_write(srv, __FILE__, __LINE__, "sbbbd",
28533 "proxy - election:",
28537 con->uri.authority,
28541 - if ((last_max == ULONG_MAX) || /* first round */
28542 - (cur_max > last_max)) {
28543 + if (host == NULL || (cur_max > last_max)) {
28544 last_max = cur_max;
28551 @@ -1155,19 +1136,20 @@
28552 case PROXY_BALANCE_FAIR:
28553 /* fair balancing */
28554 if (p->conf.debug) {
28555 - log_error_write(srv, __FILE__, __LINE__, "s",
28556 + log_error_write(srv, __FILE__, __LINE__, "s",
28557 "proxy - used fair balancing");
28560 - for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
28561 - data_proxy *host = (data_proxy *)extension->value->data[k];
28563 - if (host->is_disabled) continue;
28565 - if (host->usage < max_usage) {
28566 - max_usage = host->usage;
28569 + /* try to find the host with the lowest load */
28570 + for (k = 0, max_usage = 0; k < backends->used; k++) {
28571 + data_proxy *cur = (data_proxy *)backends->data[k];
28573 + if (cur->is_disabled) continue;
28575 + if (NULL == host || cur->usage < max_usage) {
28576 + max_usage = cur->usage;
28582 @@ -1175,89 +1157,100 @@
28583 case PROXY_BALANCE_RR:
28585 if (p->conf.debug) {
28586 - log_error_write(srv, __FILE__, __LINE__, "s",
28587 + log_error_write(srv, __FILE__, __LINE__, "s",
28588 "proxy - used round-robin balancing");
28591 /* just to be sure */
28592 - assert(extension->value->used < INT_MAX);
28594 - for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
28595 - data_proxy *host = (data_proxy *)extension->value->data[k];
28597 - if (host->is_disabled) continue;
28599 - /* first usable ndx */
28600 - if (max_usage == INT_MAX) {
28603 + assert(backends->used < INT_MAX);
28605 - /* get next ndx */
28606 - if ((int)k > host->last_used_ndx) {
28608 - host->last_used_ndx = k;
28609 + /* send each request to another host:
28613 + * if we have three hosts it is
28615 + * 1 .. 2 .. 3 .. 1 .. 2 .. 3
28621 + /* walk through the list */
28622 + last_used_backend = (data_integer *)array_get_element(p->conf.last_used_backends, extension->key->ptr);
28624 + if (NULL == last_used_backend) {
28625 + last_used_backend = data_integer_init();
28627 + buffer_copy_string_buffer(last_used_backend->key, extension->key);
28628 + last_used_backend->value = 0;
28630 + array_insert_unique(p->conf.last_used_backends, (data_unset *)last_used_backend);
28633 + /* scan all but the last host to see if they are up
28634 + * take the first running host */
28635 + for (k = last_used_backend->value + 1; (int)(k % backends->used) != last_used_backend->value; k++) {
28636 + data_proxy *cur = (data_proxy *)backends->data[k % backends->used];
28638 + if (cur->is_disabled) continue;
28642 + last_used_backend->value = k;
28647 - /* didn't found a higher id, wrap to the start */
28648 - if (ndx != -1 && max_usage != INT_MAX) {
28651 + if (NULL == host) {
28652 + /* we found nothing better, fallback to the last used backend
28653 + * and check if it is still up */
28654 + host = (data_proxy *)backends->data[last_used_backend->value];
28656 + if (host->is_disabled) host = NULL;
28664 - /* found a server */
28666 - data_proxy *host = (data_proxy *)extension->value->data[ndx];
28669 - * if check-local is disabled, use the uri.path handler
28673 - /* init handler-context */
28674 - handler_ctx *hctx;
28675 - hctx = handler_ctx_init();
28677 - hctx->path_info_offset = path_info_offset;
28678 - hctx->remote_conn = con;
28679 - hctx->plugin_data = p;
28680 - hctx->host = host;
28682 - con->plugin_ctx[p->id] = hctx;
28686 - con->mode = p->id;
28688 - if (p->conf.debug) {
28689 - log_error_write(srv, __FILE__, __LINE__, "sbd",
28690 - "proxy - found a host",
28691 - host->host, host->port);
28694 - return HANDLER_GO_ON;
28696 - /* no handler found */
28697 + /* we havn't found a host */
28698 + if (NULL == host) {
28699 con->http_status = 500;
28701 - log_error_write(srv, __FILE__, __LINE__, "sb",
28702 - "no proxy-handler found for:",
28704 + log_error_write(srv, __FILE__, __LINE__, "sb",
28705 + "no proxy-handler found for:",
28709 return HANDLER_FINISHED;
28712 + /* init handler-context */
28713 + hctx = handler_ctx_init();
28715 + hctx->path_info_offset = path_info_offset;
28716 + hctx->remote_conn = con;
28717 + hctx->plugin_data = p;
28718 + hctx->host = host;
28720 + con->plugin_ctx[p->id] = hctx;
28724 + /* we handle this request */
28725 + con->mode = p->id;
28727 + if (p->conf.debug) {
28728 + log_error_write(srv, __FILE__, __LINE__, "sbd",
28729 + "proxy - found a host",
28730 + host->host, host->port);
28733 return HANDLER_GO_ON;
28736 static handler_t mod_proxy_connection_close_callback(server *srv, connection *con, void *p_d) {
28737 plugin_data *p = p_d;
28740 proxy_connection_close(srv, con->plugin_ctx[p->id]);
28742 return HANDLER_GO_ON;
28743 @@ -1276,11 +1269,11 @@
28745 for (i = 0; i < srv->config_context->used; i++) {
28746 plugin_config *s = p->config_storage[i];
28748 - if (!s) continue;
28750 + if (!s) continue;
28752 /* get the extensions for all configs */
28755 for (k = 0; k < s->extensions->used; k++) {
28756 data_array *extension = (data_array *)s->extensions->data[k];
28758 @@ -1290,8 +1283,8 @@
28760 if (!host->is_disabled ||
28761 srv->cur_ts - host->disable_ts < 5) continue;
28763 - log_error_write(srv, __FILE__, __LINE__, "sbd",
28765 + log_error_write(srv, __FILE__, __LINE__, "sbd",
28766 "proxy - re-enabled:",
28767 host->host, host->port);
28769 @@ -1317,8 +1310,8 @@
28770 p->handle_uri_clean = mod_proxy_check_extension;
28771 p->handle_subrequest = mod_proxy_handle_subrequest;
28772 p->handle_trigger = mod_proxy_trigger;
28780 --- ../lighttpd-1.4.11/src/mod_proxy_core.c 1970-01-01 03:00:00.000000000 +0300
28781 +++ lighttpd-1.4.12/src/mod_proxy_core.c 2006-07-18 17:34:32.000000000 +0300
28783 +#include <string.h>
28784 +#include <stdlib.h>
28785 +#include <fcntl.h>
28786 +#include <errno.h>
28787 +#include <ctype.h>
28789 +#include "buffer.h"
28790 +#include "array.h"
28794 +#include "plugin.h"
28795 +#include "joblist.h"
28796 +#include "sys-files.h"
28797 +#include "inet_ntop_cache.h"
28798 +#include "http_resp.h"
28799 +#include "http_chunk.h"
28800 +#include "crc32.h"
28802 +#include "mod_proxy_core_pool.h"
28803 +#include "mod_proxy_core_backend.h"
28804 +#include "mod_proxy_core_backlog.h"
28805 +#include "mod_proxy_core_rewrites.h"
28807 +#define CONFIG_PROXY_CORE_REWRITE_REQUEST "proxy-core.rewrite-request"
28808 +#define CONFIG_PROXY_CORE_REWRITE_RESPONSE "proxy-core.rewrite-response"
28811 + PROXY_PROTOCOL_UNSET,
28812 + PROXY_PROTOCOL_HTTP,
28813 + PROXY_PROTOCOL_HTTPS,
28814 + PROXY_PROTOCOL_FASTCGI,
28815 + PROXY_PROTOCOL_SCGI
28816 +} proxy_protocol_t;
28819 + proxy_backends *backends;
28821 + proxy_backlog *backlog;
28823 + proxy_rewrites *request_rewrites;
28824 + proxy_rewrites *response_rewrites;
28828 + proxy_balance_t balancer;
28829 + proxy_protocol_t protocol;
28837 + array *possible_balancers;
28838 + array *possible_protocols;
28840 + /* for parsing only */
28841 + array *backends_arr;
28842 + buffer *protocol_buf;
28843 + buffer *balance_buf;
28845 + buffer *replace_buf;
28847 + plugin_config **config_storage;
28849 + plugin_config conf;
28852 +int array_insert_int(array *a, const char *key, int val) {
28853 + data_integer *di;
28855 + if (NULL == (di = (data_integer *)array_get_unused_element(a, TYPE_INTEGER))) {
28856 + di = data_integer_init();
28859 + buffer_copy_string(di->key, key);
28861 + array_insert_unique(a, (data_unset *)di);
28866 +INIT_FUNC(mod_proxy_core_init) {
28869 + p = calloc(1, sizeof(*p));
28871 + /* create some backends as long as we don't have the config-parser */
28873 + p->possible_balancers = array_init();
28874 + array_insert_int(p->possible_balancers, "fair", PROXY_BALANCE_FAIR);
28875 + array_insert_int(p->possible_balancers, "hash", PROXY_BALANCE_RR);
28876 + array_insert_int(p->possible_balancers, "round-robin", PROXY_BALANCE_HASH);
28878 + p->possible_protocols = array_init();
28879 + array_insert_int(p->possible_protocols, "http", PROXY_PROTOCOL_HTTP);
28880 + array_insert_int(p->possible_protocols, "fastcgi", PROXY_PROTOCOL_FASTCGI);
28881 + array_insert_int(p->possible_protocols, "scgi", PROXY_PROTOCOL_SCGI);
28882 + array_insert_int(p->possible_protocols, "https", PROXY_PROTOCOL_HTTPS);
28884 + p->balance_buf = buffer_init();
28885 + p->protocol_buf = buffer_init();
28886 + p->replace_buf = buffer_init();
28887 + p->backends_arr = array_init();
28889 + p->resp = http_response_init();
28894 +FREE_FUNC(mod_proxy_core_free) {
28895 + plugin_data *p = p_d;
28897 + if (!p) return HANDLER_GO_ON;
28899 + if (p->config_storage) {
28901 + for (i = 0; i < srv->config_context->used; i++) {
28902 + plugin_config *s = p->config_storage[i];
28904 + if (!s) continue;
28906 + proxy_backends_free(s->backends);
28907 + proxy_backlog_free(s->backlog);
28912 + free(p->config_storage);
28915 + array_free(p->possible_protocols);
28916 + array_free(p->possible_balancers);
28917 + array_free(p->backends_arr);
28919 + buffer_free(p->balance_buf);
28920 + buffer_free(p->protocol_buf);
28921 + buffer_free(p->replace_buf);
28923 + http_response_free(p->resp);
28927 + return HANDLER_GO_ON;
28930 +static handler_t mod_proxy_core_config_parse_rewrites(proxy_rewrites *dest, array *src, const char *config_key) {
28934 + if (NULL != (du = array_get_element(src, config_key))) {
28935 + data_array *keys = (data_array *)du;
28937 + if (keys->type != TYPE_ARRAY) {
28938 + ERROR("%s = <...>",
28941 + return HANDLER_ERROR;
28945 + * proxy-core.rewrite-request = (
28946 + * "_uri" => ( ... )
28950 + for (j = 0; j < keys->value->used; j++) {
28952 + data_array *headers = (data_array *)keys->value->data[j];
28954 + /* keys->key should be "_uri" and the value a array of rewrite */
28955 + if (headers->type != TYPE_ARRAY) {
28956 + ERROR("%s = ( %s => <...> ) has to a array",
28958 + BUF_STR(headers->key));
28960 + return HANDLER_ERROR;
28963 + TRACE("%s: header-field: %s", config_key, BUF_STR(headers->key));
28965 + if (headers->value->used > 1) {
28966 + ERROR("%s = ( %s => <...> ) has to a array with only one element",
28968 + BUF_STR(headers->key));
28970 + return HANDLER_ERROR;
28974 + for (k = 0; k < headers->value->used; k++) {
28975 + data_string *rewrites = (data_string *)headers->value->data[k];
28976 + proxy_rewrite *rw;
28978 + /* keys->key should be "_uri" and the value a array of rewrite */
28979 + if (rewrites->type != TYPE_STRING) {
28980 + ERROR("%s = ( \"%s\" => ( \"%s\" => <value> ) ) has to a string",
28982 + BUF_STR(headers->key),
28983 + BUF_STR(rewrites->key));
28985 + return HANDLER_ERROR;
28988 + TRACE("%s: rewrites-field: %s -> %s",
28990 + BUF_STR(headers->key),
28991 + BUF_STR(rewrites->key));
28993 + rw = proxy_rewrite_init();
28995 + if (0 != proxy_rewrite_set_regex(rw, rewrites->key)) {
28996 + return HANDLER_ERROR;
28998 + buffer_copy_string_buffer(rw->replace, rewrites->value);
28999 + buffer_copy_string_buffer(rw->match, rewrites->key);
29000 + buffer_copy_string_buffer(rw->header, headers->key);
29002 + proxy_rewrites_add(dest, rw);
29007 + return HANDLER_GO_ON;
29011 +SETDEFAULTS_FUNC(mod_proxy_core_set_defaults) {
29012 + plugin_data *p = p_d;
29015 + config_values_t cv[] = {
29016 + { "proxy-core.backends", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
29017 + { "proxy-core.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
29018 + { "proxy-core.balancer", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
29019 + { "proxy-core.protocol", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
29020 + { CONFIG_PROXY_CORE_REWRITE_REQUEST, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
29021 + { CONFIG_PROXY_CORE_REWRITE_RESPONSE, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },/* 5 */
29022 + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
29025 + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
29027 + for (i = 0; i < srv->config_context->used; i++) {
29028 + plugin_config *s;
29030 + proxy_backend *backend;
29032 + array_reset(p->backends_arr);
29033 + buffer_reset(p->balance_buf);
29034 + buffer_reset(p->protocol_buf);
29036 + s = malloc(sizeof(plugin_config));
29038 + s->balancer = PROXY_BALANCE_UNSET;
29039 + s->protocol = PROXY_PROTOCOL_UNSET;
29040 + s->backends = proxy_backends_init();
29041 + s->backlog = proxy_backlog_init();
29042 + s->response_rewrites = proxy_rewrites_init();
29043 + s->request_rewrites = proxy_rewrites_init();
29045 + cv[0].destination = p->backends_arr;
29046 + cv[1].destination = &(s->debug);
29047 + cv[2].destination = p->balance_buf; /* parse into a constant */
29048 + cv[3].destination = p->protocol_buf; /* parse into a constant */
29050 + buffer_reset(p->balance_buf);
29052 + p->config_storage[i] = s;
29053 + ca = ((data_config *)srv->config_context->data[i])->value;
29055 + if (0 != config_insert_values_global(srv, ca, cv)) {
29056 + return HANDLER_ERROR;
29059 + if (!buffer_is_empty(p->balance_buf)) {
29060 + data_integer *di;
29062 + if (NULL == (di = (data_integer *)array_get_element(p->possible_balancers, BUF_STR(p->balance_buf)))) {
29063 + ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->balance_buf));
29065 + return HANDLER_ERROR;
29068 + s->balancer = di->value;
29071 + if (!buffer_is_empty(p->protocol_buf)) {
29072 + data_integer *di;
29074 + if (NULL == (di = (data_integer *)array_get_element(p->possible_protocols, BUF_STR(p->protocol_buf)))) {
29075 + ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->protocol_buf));
29077 + return HANDLER_ERROR;
29080 + s->protocol = di->value;
29083 + if (p->backends_arr->used) {
29084 + backend = proxy_backend_init();
29086 + /* check if the backends have a valid host-name */
29087 + for (j = 0; j < p->backends_arr->used; j++) {
29088 + data_string *ds = (data_string *)p->backends_arr->data[j];
29090 + /* the values should be ips or hostnames */
29091 + if (0 != proxy_address_pool_add_string(backend->address_pool, ds->value)) {
29092 + return HANDLER_ERROR;
29096 + proxy_backends_add(s->backends, backend);
29099 + if (HANDLER_GO_ON != mod_proxy_core_config_parse_rewrites(s->request_rewrites, ca, CONFIG_PROXY_CORE_REWRITE_REQUEST)) {
29100 + return HANDLER_ERROR;
29103 + if (HANDLER_GO_ON != mod_proxy_core_config_parse_rewrites(s->response_rewrites, ca, CONFIG_PROXY_CORE_REWRITE_RESPONSE)) {
29104 + return HANDLER_ERROR;
29108 + return HANDLER_GO_ON;
29113 + PROXY_STATE_UNSET,
29114 + PROXY_STATE_CONNECTING,
29115 + PROXY_STATE_CONNECTED,
29116 + PROXY_STATE_WRITE_REQUEST_HEADER,
29117 + PROXY_STATE_WRITE_REQUEST_BODY,
29118 + PROXY_STATE_READ_RESPONSE_HEADER,
29119 + PROXY_STATE_READ_RESPONSE_BODY
29123 + proxy_connection *proxy_con;
29124 + proxy_backend *proxy_backend;
29126 + connection *remote_con;
29128 + array *request_headers;
29134 + * - the encoded_rb is the raw network stuff
29135 + * - the rb is filtered through the stream decoder
29137 + * - wb is the normal bytes stream
29138 + * - encoded_wb is encoded for the network by the stream encoder
29140 + chunkqueue *recv;
29141 + chunkqueue *recv_raw;
29142 + chunkqueue *send_raw;
29143 + chunkqueue *send;
29145 + off_t bytes_read;
29146 + off_t content_length;
29148 + proxy_state_t state;
29151 +proxy_session *proxy_session_init(void) {
29152 + proxy_session *sess;
29154 + sess = calloc(1, sizeof(*sess));
29156 + sess->state = PROXY_STATE_UNSET;
29157 + sess->request_headers = array_init();
29159 + sess->recv = chunkqueue_init();
29160 + sess->recv_raw = chunkqueue_init();
29161 + sess->send_raw = chunkqueue_init();
29162 + sess->send = chunkqueue_init();
29164 + sess->is_chunked = 0;
29169 +void proxy_session_free(proxy_session *sess) {
29170 + if (!sess) return;
29172 + array_free(sess->request_headers);
29174 + chunkqueue_free(sess->recv);
29175 + chunkqueue_free(sess->recv_raw);
29176 + chunkqueue_free(sess->send_raw);
29177 + chunkqueue_free(sess->send);
29182 +handler_t proxy_connection_connect(proxy_connection *con) {
29185 + if (-1 == (fd = socket(con->address->addr.plain.sa_family, SOCK_STREAM, 0))) {
29188 + fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
29190 + con->sock->fd = fd;
29191 + con->sock->fde_ndx = -1;
29192 + con->sock->type = IOSOCKET_TYPE_SOCKET;
29194 + if (-1 == connect(fd, &(con->address->addr.plain), sizeof(con->address->addr))) {
29196 + case EINPROGRESS:
29199 + return HANDLER_WAIT_FOR_EVENT;
29202 + con->sock->fd = -1;
29204 + return HANDLER_ERROR;
29208 + return HANDLER_GO_ON;
29212 + * event-handler for idling connections
29214 + * unused (idling) keep-alive connections are not bound to a session
29215 + * and need their own event-handler
29217 + * if the connection closes (we get a FDEVENT_IN), close our side too and
29218 + * let the trigger-func handle the cleanup
29220 + * @see proxy_trigger
29224 +static handler_t proxy_handle_fdevent_idle(void *s, void *ctx, int revents) {
29225 + server *srv = (server *)s;
29226 + proxy_connection *proxy_con = ctx;
29228 + if (revents & FDEVENT_IN) {
29229 + switch (proxy_con->state) {
29230 + case PROXY_CONNECTION_STATE_IDLE:
29231 + proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29233 + /* close + unregister have to be in the same call,
29234 + * otherwise we get a events for a re-opened fd */
29236 + fdevent_event_del(srv->ev, proxy_con->sock);
29239 + case PROXY_CONNECTION_STATE_CLOSED:
29240 + /* poll() is state-driven, we will get events as long as it isn't disabled
29241 + * the close() above should disable the events too */
29242 + ERROR("%s", "hurry up buddy, I got another event for a closed idle-connection");
29245 + ERROR("invalid connection state: %d, should be idle", proxy_con->state);
29250 + return HANDLER_GO_ON;
29253 +void chunkqueue_skip(chunkqueue *cq, off_t skip) {
29256 + for (c = cq->first; c && skip; c = c->next) {
29257 + if (skip > c->mem->used - c->offset - 1) {
29258 + skip -= c->mem->used - c->offset - 1;
29260 + c->offset += skip;
29268 +int proxy_http_stream_decoder(server *srv, proxy_session *sess, chunkqueue *raw, chunkqueue *decoded) {
29271 + if (sess->is_chunked) {
29273 + /* the start should always be a chunk-length */
29274 + off_t chunk_len = 0;
29275 + char *err = NULL;
29276 + int chunklen_strlen = 0;
29278 + off_t we_have = 0, we_need = 0;
29282 + chunk_len = strtol(BUF_STR(c->mem) + c->offset, &err, 16);
29283 + if (!(*err == ' ' || *err == '\r' || *err == ';')) {
29284 + if (*err == '\0') {
29285 + /* we just need more data */
29291 + if (chunk_len < 0) {
29292 + ERROR("chunk_len is negative: %Ld", chunk_len);
29296 + chunklen_strlen = err - (BUF_STR(c->mem) + c->offset);
29297 + chunklen_strlen++; /* skip the err-char */
29300 + ch = BUF_STR(c->mem)[c->offset + chunklen_strlen];
29305 + /* bingo, chunk-header is finished */
29310 + chunklen_strlen++;
29311 + } while (ch != '\n' && c != '\0');
29313 + if (ch != '\n') {
29314 + ERROR("%s", "missing the CRLF");
29318 + we_need = chunk_len + chunklen_strlen + 2;
29319 + /* do we have the full chunk ? */
29320 + for (c = raw->first; c; c = c->next) {
29321 + we_have += c->mem->used - 1 - c->offset;
29323 + /* we have enough, jump out */
29324 + if (we_have > we_need) break;
29327 + /* get more data */
29328 + if (we_have < we_need) {
29332 + /* skip the chunk-header */
29333 + chunkqueue_skip(raw, chunklen_strlen);
29335 + /* final chunk */
29336 + if (chunk_len == 0) {
29337 + chunkqueue_skip(raw, 2);
29342 + /* we have enough, copy the data */
29343 + for (c = raw->first; c && chunk_len; c = c->next) {
29344 + off_t we_want = 0;
29345 + buffer *b = chunkqueue_get_append_buffer(decoded);
29347 + we_want = chunk_len > (c->mem->used - c->offset - 1) ? c->mem->used - c->offset - 1: chunk_len;
29349 + buffer_copy_string_len(b, c->mem->ptr + c->offset, we_want);
29351 + c->offset += we_want;
29352 + chunk_len -= we_want;
29355 + /* skip the \r\n */
29356 + chunkqueue_skip(raw, 2);
29358 + /* we are done, give the connection to someone else */
29359 + chunkqueue_remove_finished_chunks(raw);
29362 + /* no chunked encoding, ok, perhaps a content-length ? */
29364 + chunkqueue_remove_finished_chunks(raw);
29365 + for (c = raw->first; c; c = c->next) {
29368 + if (c->mem->used == 0) continue;
29370 + b = chunkqueue_get_append_buffer(decoded);
29372 + sess->bytes_read += c->mem->used - c->offset - 1;
29374 + buffer_copy_string_len(b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
29376 + c->offset = c->mem->used - 1;
29378 + if (sess->bytes_read == sess->content_length) {
29383 + if (sess->bytes_read == sess->content_length) {
29384 + return 1; /* finished */
29390 +/* don't call any proxy functions directly */
29391 +static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) {
29392 + server *srv = (server *)s;
29393 + proxy_session *sess = ctx;
29395 + if (revents & FDEVENT_OUT) {
29396 + switch (sess->state) {
29397 + case PROXY_STATE_CONNECTING: /* delayed connect */
29398 + case PROXY_STATE_WRITE_REQUEST_HEADER:
29399 + case PROXY_STATE_WRITE_REQUEST_BODY:
29400 + /* we are still connection */
29402 + joblist_append(srv, sess->remote_con);
29405 + ERROR("oops, unexpected state for fdevent-out %d", sess->state);
29408 + } else if (revents & FDEVENT_IN) {
29411 + switch (sess->state) {
29412 + case PROXY_STATE_READ_RESPONSE_HEADER:
29413 + /* call our header parser */
29414 + joblist_append(srv, sess->remote_con);
29416 + case PROXY_STATE_READ_RESPONSE_BODY:
29417 + /* we should be in the WRITE state now,
29418 + * just read in the content and forward it to the outgoing connection
29421 + chunkqueue_remove_finished_chunks(sess->recv_raw);
29422 + switch (srv->network_backend_read(srv, sess->remote_con, sess->proxy_con->sock, sess->recv_raw)) {
29423 + case NETWORK_STATUS_CONNECTION_CLOSE:
29424 + fdevent_event_del(srv->ev,sess->proxy_con->sock);
29426 + /* the connection is gone
29427 + * make the connect */
29428 + sess->remote_con->file_finished = 1;
29429 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29431 + case NETWORK_STATUS_SUCCESS:
29432 + /* read even more, do we have all the content */
29434 + /* how much do we want to read ? */
29436 + /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
29438 + switch (proxy_http_stream_decoder(srv, sess, sess->recv_raw, sess->recv)) {
29446 + /* we are done */
29447 + sess->remote_con->file_finished = 1;
29451 + chunkqueue_remove_finished_chunks(sess->recv_raw);
29453 + /* copy the content to the next cq */
29454 + for (c = sess->recv->first; c; c = c->next) {
29455 + if (c->mem->used == 0) continue;
29457 + http_chunk_append_mem(srv, sess->remote_con, c->mem->ptr + c->offset, c->mem->used - c->offset);
29459 + c->offset = c->mem->used - 1;
29462 + chunkqueue_remove_finished_chunks(sess->recv);
29464 + if (sess->remote_con->file_finished) {
29465 + /* send final HTTP-Chunk packet */
29466 + http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
29471 + ERROR("%s", "oops, we failed to read");
29475 + joblist_append(srv, sess->remote_con);
29478 + ERROR("oops, unexpected state for fdevent-in %d", sess->state);
29483 + if (revents & FDEVENT_HUP) {
29484 + /* someone closed our connection */
29485 + switch (sess->state) {
29486 + case PROXY_STATE_CONNECTING:
29487 + /* let the getsockopt() catch this */
29488 + joblist_append(srv, sess->remote_con);
29491 + ERROR("oops, unexpected state for fdevent-hup %d", sess->state);
29496 + return HANDLER_GO_ON;
29499 +int pcre_replace(pcre *match, buffer *replace, buffer *match_buf, buffer *result) {
29500 + const char *pattern = replace->ptr;
29501 + size_t pattern_len = replace->used - 1;
29507 + if ((n = pcre_exec(match, NULL, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
29508 + if (n != PCRE_ERROR_NOMATCH) {
29512 + const char **list;
29513 + size_t start, end;
29517 + pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
29519 + /* search for $[0-9] */
29521 + buffer_reset(result);
29523 + start = 0; end = pattern_len;
29524 + for (k = 0; k < pattern_len; k++) {
29525 + if ((pattern[k] == '$') &&
29526 + isdigit((unsigned char)pattern[k + 1])) {
29529 + size_t num = pattern[k + 1] - '0';
29533 + buffer_append_string_len(result, pattern + start, end - start);
29535 + /* n is always > 0 */
29536 + if (num < (size_t)n) {
29537 + buffer_append_string(result, list[num]);
29545 + buffer_append_string_len(result, pattern + start, pattern_len - start);
29554 + * generate a HTTP/1.1 proxy request from the set of request-headers
29556 + * TODO: this is HTTP-proxy specific and will be moved moved into a separate backed
29559 +int proxy_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
29563 + b = chunkqueue_get_append_buffer(cq);
29565 + /* request line */
29566 + buffer_copy_string(b, get_http_method_name(con->request.http_method));
29567 + BUFFER_APPEND_STRING_CONST(b, " ");
29569 + /* check if we want to rewrite the uri */
29571 + for (i = 0; i < p->conf.request_rewrites->used; i++) {
29572 + proxy_rewrite *rw = p->conf.request_rewrites->ptr[i];
29574 + if (buffer_is_equal_string(rw->header, CONST_STR_LEN("_uri"))) {
29577 + if ((ret = pcre_replace(rw->regex, rw->replace, con->request.uri, p->replace_buf)) < 0) {
29579 + case PCRE_ERROR_NOMATCH:
29580 + /* hmm, ok. no problem */
29581 + buffer_append_string_buffer(b, con->request.uri);
29584 + TRACE("oops, pcre_replace failed with: %d", ret);
29588 + buffer_append_string_buffer(b, p->replace_buf);
29595 + if (i == p->conf.request_rewrites->used) {
29597 + buffer_append_string_buffer(b, con->request.uri);
29600 + BUFFER_APPEND_STRING_CONST(b, " HTTP/1.1\r\n");
29602 + for (i = 0; i < sess->request_headers->used; i++) {
29605 + ds = (data_string *)sess->request_headers->data[i];
29607 + buffer_append_string_buffer(b, ds->key);
29608 + BUFFER_APPEND_STRING_CONST(b, ": ");
29609 + buffer_append_string_buffer(b, ds->value);
29610 + BUFFER_APPEND_STRING_CONST(b, "\r\n");
29613 + BUFFER_APPEND_STRING_CONST(b, "\r\n");
29618 +void proxy_set_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
29619 + data_string *ds_dst;
29621 + if (NULL != (ds_dst = (data_string *)array_get_element(hdrs, key))) {
29622 + buffer_copy_string_len(ds_dst->value, value, val_len);
29626 + if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
29627 + ds_dst = data_string_init();
29630 + buffer_copy_string_len(ds_dst->key, key, key_len);
29631 + buffer_copy_string_len(ds_dst->value, value, val_len);
29632 + array_insert_unique(hdrs, (data_unset *)ds_dst);
29635 +void proxy_append_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
29636 + data_string *ds_dst;
29638 + if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
29639 + ds_dst = data_string_init();
29642 + buffer_copy_string_len(ds_dst->key, key, key_len);
29643 + buffer_append_string_len(ds_dst->value, value, val_len);
29644 + array_insert_unique(hdrs, (data_unset *)ds_dst);
29649 + * build the request-header array and call the backend specific request formater
29650 + * to fill the chunkqueue
29652 +int proxy_get_request_header(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
29653 + /* request line */
29654 + const char *remote_ip;
29657 + remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
29658 + proxy_append_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-For"), remote_ip, strlen(remote_ip));
29660 + /* http_host is NOT is just a pointer to a buffer
29661 + * which is NULL if it is not set */
29662 + if (con->request.http_host &&
29663 + !buffer_is_empty(con->request.http_host)) {
29664 + proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Host"), CONST_BUF_LEN(con->request.http_host));
29666 + if (con->conf.is_ssl) {
29667 + proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("https"));
29669 + proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("http"));
29672 + /* request header */
29673 + for (i = 0; i < con->request.headers->used; i++) {
29677 + ds = (data_string *)con->request.headers->data[i];
29679 + if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
29681 + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
29682 + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
29684 + for (k = 0; k < p->conf.request_rewrites->used; k++) {
29685 + proxy_rewrite *rw = p->conf.request_rewrites->ptr[k];
29687 + if (buffer_is_equal(rw->header, ds->key)) {
29690 + if ((ret = pcre_replace(rw->regex, rw->replace, ds->value, p->replace_buf)) < 0) {
29692 + case PCRE_ERROR_NOMATCH:
29693 + /* hmm, ok. no problem */
29694 + proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
29697 + TRACE("oops, pcre_replace failed with: %d", ret);
29701 + proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(p->replace_buf));
29708 + if (k == p->conf.request_rewrites->used) {
29709 + proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
29713 + proxy_get_request_chunk(srv, con, p, sess, sess->send_raw);
29719 + * parse the response header
29721 + * NOTE: this can be used by all backends as they all send a HTTP-Response a clean block
29722 + * - fastcgi needs some decoding for the protocol
29724 +parse_status_t proxy_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
29725 + int have_content_length = 0;
29728 + http_response_reset(p->resp);
29730 + switch (http_response_parse_cq(cq, p->resp)) {
29731 + case PARSE_ERROR:
29732 + /* parsing failed */
29734 + return PARSE_ERROR;
29735 + case PARSE_NEED_MORE:
29736 + return PARSE_NEED_MORE;
29737 + case PARSE_SUCCESS:
29738 + con->http_status = p->resp->status;
29740 + chunkqueue_remove_finished_chunks(cq);
29742 + sess->content_length = -1;
29744 + /* copy the http-headers */
29745 + for (i = 0; i < p->resp->headers->used; i++) {
29746 + const char *ign[] = { "Status", "Connection", NULL };
29750 + data_string *header = (data_string *)p->resp->headers->data[i];
29752 + /* some headers are ignored by default */
29753 + for (j = 0; ign[j]; j++) {
29754 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
29756 + if (ign[j]) continue;
29758 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
29759 + /* CGI/1.1 rev 03 - 7.2.1.2 */
29760 + if (con->http_status == 0) con->http_status = 302;
29761 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
29762 + have_content_length = 1;
29764 + sess->content_length = strtol(header->value->ptr, NULL, 10);
29766 + if (sess->content_length < 0) {
29767 + return PARSE_ERROR;
29769 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Transfer-Encoding"))) {
29770 + if (strstr(header->value->ptr, "chunked")) {
29771 + sess->is_chunked = 1;
29773 + /* ignore the header */
29777 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
29778 + ds = data_response_init();
29782 + buffer_copy_string_buffer(ds->key, header->key);
29784 + for (k = 0; k < p->conf.response_rewrites->used; k++) {
29785 + proxy_rewrite *rw = p->conf.response_rewrites->ptr[k];
29787 + if (buffer_is_equal(rw->header, header->key)) {
29790 + if ((ret = pcre_replace(rw->regex, rw->replace, header->value, p->replace_buf)) < 0) {
29792 + case PCRE_ERROR_NOMATCH:
29793 + /* hmm, ok. no problem */
29794 + buffer_append_string_buffer(ds->value, header->value);
29797 + TRACE("oops, pcre_replace failed with: %d", ret);
29801 + buffer_append_string_buffer(ds->value, p->replace_buf);
29808 + if (k == p->conf.response_rewrites->used) {
29809 + buffer_copy_string_buffer(ds->value, header->value);
29812 + array_insert_unique(con->response.headers, (data_unset *)ds);
29815 + /* does the client allow us to send chunked encoding ? */
29816 + if (con->request.http_version == HTTP_VERSION_1_1 &&
29817 + !have_content_length) {
29818 + con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
29824 + return PARSE_SUCCESS; /* we have a full header */
29827 +/* we are event-driven
29829 + * the first entry is connect() call, if the doesn't need a event
29832 + * - connect (+ delayed connect)
29833 + * - write header + content
29834 + * - read header + content
29836 + * as soon as have read the response header we switch con->file_started and return HANDLER_GO_ON to
29837 + * tell the core we are ready to stream out the content.
29839 +handler_t proxy_state_engine(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
29840 + /* do we have a connection ? */
29842 + if (sess->state == PROXY_STATE_UNSET) {
29843 + /* we are not started yet */
29844 + switch(proxy_connection_connect(sess->proxy_con)) {
29845 + case HANDLER_WAIT_FOR_EVENT:
29846 + /* waiting on the connect call */
29848 + fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
29849 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
29851 + sess->state = PROXY_STATE_CONNECTING;
29852 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
29854 + return HANDLER_WAIT_FOR_EVENT;
29855 + case HANDLER_GO_ON:
29856 + /* we are connected */
29857 + sess->state = PROXY_STATE_CONNECTED;
29858 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
29859 + fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
29862 + case HANDLER_ERROR:
29864 + /* not good, something failed */
29865 + return HANDLER_ERROR;
29868 + } else if (sess->state == PROXY_STATE_CONNECTING) {
29869 + int socket_error;
29870 + socklen_t socket_error_len = sizeof(socket_error);
29872 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
29874 + if (0 != getsockopt(sess->proxy_con->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
29875 + ERROR("getsockopt failed:", strerror(errno));
29877 + return HANDLER_ERROR;
29879 + if (socket_error != 0) {
29880 + switch (socket_error) {
29881 + case ECONNREFUSED:
29882 + /* there is no-one on the other side */
29883 + sess->proxy_con->address->disabled_until = srv->cur_ts + 2;
29885 + TRACE("address %s refused us, disabling for 2 sec", sess->proxy_con->address->name->ptr);
29887 + case EHOSTUNREACH:
29888 + /* there is no-one on the other side */
29889 + sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
29891 + TRACE("host %s is unreachable, disabling for 60 sec", sess->proxy_con->address->name->ptr);
29894 + sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
29896 + TRACE("connected finally failed: %s (%d)", strerror(socket_error), socket_error);
29898 + TRACE("connect to address %s failed and I don't know why, disabling for 10 sec", sess->proxy_con->address->name->ptr);
29903 + sess->proxy_con->address->state = PROXY_ADDRESS_STATE_DISABLED;
29905 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29906 + return HANDLER_COMEBACK;
29909 + sess->state = PROXY_STATE_CONNECTED;
29910 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
29913 + if (sess->state == PROXY_STATE_CONNECTED) {
29914 + /* build the header */
29915 + proxy_get_request_header(srv, con, p, sess);
29917 + sess->state = PROXY_STATE_WRITE_REQUEST_HEADER;
29920 + switch (sess->state) {
29921 + case PROXY_STATE_WRITE_REQUEST_HEADER:
29922 + /* create the request-packet */
29923 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
29925 + switch (srv->network_backend_write(srv, con, sess->proxy_con->sock, sess->send_raw)) {
29926 + case NETWORK_STATUS_SUCCESS:
29927 + sess->state = PROXY_STATE_WRITE_REQUEST_BODY;
29929 + case NETWORK_STATUS_WAIT_FOR_EVENT:
29930 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
29932 + return HANDLER_WAIT_FOR_EVENT;
29933 + case NETWORK_STATUS_CONNECTION_CLOSE:
29934 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29936 + /* this connection is closed, restart the request with a new connection */
29938 + return HANDLER_COMEBACK;
29940 + return HANDLER_ERROR;
29942 + /* fall through */
29943 + case PROXY_STATE_WRITE_REQUEST_BODY:
29944 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
29945 + sess->state = PROXY_STATE_READ_RESPONSE_HEADER;
29947 + case PROXY_STATE_READ_RESPONSE_HEADER:
29948 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
29950 + chunkqueue_remove_finished_chunks(sess->recv_raw);
29952 + switch (srv->network_backend_read(srv, con, sess->proxy_con->sock, sess->recv_raw)) {
29953 + case NETWORK_STATUS_SUCCESS:
29954 + /* we read everything from the socket, do we have a full header ? */
29956 + switch (proxy_parse_response_header(srv, con, p, sess, sess->recv_raw)) {
29957 + case PARSE_ERROR:
29958 + con->http_status = 502; /* bad gateway */
29960 + return HANDLER_FINISHED;
29961 + case PARSE_NEED_MORE:
29962 + /* we need more */
29963 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
29965 + return HANDLER_WAIT_FOR_EVENT;
29966 + case PARSE_SUCCESS:
29969 + return HANDLER_ERROR;
29972 + con->file_started = 1;
29974 + sess->state = PROXY_STATE_READ_RESPONSE_BODY;
29977 + * set the event to pass the content through to the server
29979 + * this triggers the event-handler
29980 + * @see proxy_handle_fdevent
29982 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
29984 + return HANDLER_GO_ON; /* tell http_response_prepare that we are done with the header */
29985 + case NETWORK_STATUS_WAIT_FOR_EVENT:
29986 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
29987 + return HANDLER_WAIT_FOR_EVENT;
29988 + case NETWORK_STATUS_CONNECTION_CLOSE:
29989 + if (chunkqueue_length(sess->recv_raw) == 0) {
29990 + /* the connection went away before we got something back */
29991 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29994 + * we might run into a 'race-condition'
29996 + * 1. proxy-con is keep-alive, idling and just being closed (FDEVENT_IN) [fd=27]
29997 + * 2. new connection comes in, we use the idling connection [fd=14]
29998 + * 3. we write(), successful [to fd=27]
29999 + * 3. we read() ... and finally receive the close-event for the connection
30002 + con->http_status = 500;
30004 + ERROR("++ %s", "oops, connection got closed while we were reading from it");
30005 + return HANDLER_FINISHED;
30008 + ERROR("%s", "conn-close after header-read");
30012 + ERROR("++ %s", "oops, something went wrong while reading");
30013 + return HANDLER_ERROR;
30015 + case PROXY_STATE_READ_RESPONSE_BODY:
30016 + /* if we do everything right, we won't get call for this state-anymore */
30018 + ERROR("%s", "PROXY_STATE_READ_RESPONSE_BODY");
30023 + return HANDLER_GO_ON;
30026 +proxy_backend *proxy_get_backend(server *srv, connection *con, plugin_data *p) {
30029 + for (i = 0; i < p->conf.backends->used; i++) {
30030 + proxy_backend *backend = p->conf.backends->ptr[i];
30039 + * choose a available address from the address-pool
30041 + * the backend has different balancers
30043 +proxy_address *proxy_backend_balance(server *srv, connection *con, proxy_backend *backend) {
30045 + proxy_address_pool *address_pool = backend->address_pool;
30046 + unsigned long last_max; /* for the HASH balancer */
30047 + proxy_address *address = NULL, *cur_address = NULL;
30048 + int active_addresses = 0, rand_ndx;
30050 + switch(backend->balancer) {
30051 + case PROXY_BALANCE_HASH:
30052 + /* hash balancing */
30054 + for (i = 0, last_max = ULONG_MAX; i < address_pool->used; i++) {
30055 + unsigned long cur_max;
30057 + cur_address = address_pool->ptr[i];
30059 + if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30061 + cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
30062 + generate_crc32c(CONST_BUF_LEN(cur_address->name)) + /* we can cache this */
30063 + generate_crc32c(CONST_BUF_LEN(con->uri.authority));
30065 + TRACE("hash-election: %s - %s - %s: %ld",
30066 + con->uri.path->ptr,
30067 + cur_address->name->ptr,
30068 + con->uri.authority->ptr,
30071 + if (address == NULL || (cur_max > last_max)) {
30072 + last_max = cur_max;
30074 + address = cur_address;
30079 + case PROXY_BALANCE_FAIR:
30080 + /* fair balancing */
30082 + for (i = 0; i < address_pool->used; i++) {
30083 + cur_address = address_pool->ptr[i];
30085 + if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30087 + /* the address is up, use it */
30089 + address = cur_address;
30095 + case PROXY_BALANCE_RR:
30096 + /* round robin */
30099 + * instead of real RoundRobin we just do a RandomSelect
30101 + * it is state-less and has the same distribution
30104 + active_addresses = 0;
30106 + for (i = 0; i < address_pool->used; i++) {
30107 + cur_address = address_pool->ptr[i];
30109 + if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30111 + active_addresses++;
30114 + rand_ndx = (int) (1.0 * active_addresses * rand()/(RAND_MAX));
30116 + active_addresses = 0;
30117 + for (i = 0; i < address_pool->used; i++) {
30118 + cur_address = address_pool->ptr[i];
30120 + if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30122 + address = cur_address;
30124 + if (rand_ndx == active_addresses++) break;
30135 +static int mod_proxy_core_patch_connection(server *srv, connection *con, plugin_data *p) {
30137 + plugin_config *s = p->config_storage[0];
30139 + /* global defaults */
30140 + PATCH_OPTION(balancer);
30141 + PATCH_OPTION(debug);
30142 + PATCH_OPTION(backends);
30143 + PATCH_OPTION(backlog);
30144 + PATCH_OPTION(protocol);
30145 + PATCH_OPTION(request_rewrites);
30146 + PATCH_OPTION(response_rewrites);
30148 + /* skip the first, the global context */
30149 + for (i = 1; i < srv->config_context->used; i++) {
30150 + data_config *dc = (data_config *)srv->config_context->data[i];
30151 + s = p->config_storage[i];
30153 + /* condition didn't match */
30154 + if (!config_check_cond(srv, con, dc)) continue;
30156 + /* merge config */
30157 + for (j = 0; j < dc->value->used; j++) {
30158 + data_unset *du = dc->value->data[j];
30160 + if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy-core.backends"))) {
30161 + PATCH_OPTION(backends);
30162 + PATCH_OPTION(backlog);
30163 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy-core.debug"))) {
30164 + PATCH_OPTION(debug);
30165 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy-core.balancer"))) {
30166 + PATCH_OPTION(balancer);
30167 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy-core.protocol"))) {
30168 + PATCH_OPTION(protocol);
30169 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_REWRITE_REQUEST))) {
30170 + PATCH_OPTION(request_rewrites);
30171 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_REWRITE_RESPONSE))) {
30172 + PATCH_OPTION(response_rewrites);
30181 +SUBREQUEST_FUNC(mod_proxy_core_check_extension) {
30182 + plugin_data *p = p_d;
30183 + proxy_session *sess = con->plugin_ctx[p->id]; /* if this is the second round, sess is already prepared */
30185 + /* check if we have a matching conditional for this request */
30187 + if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
30189 + mod_proxy_core_patch_connection(srv, con, p);
30191 + if (p->conf.backends->used == 0) return HANDLER_GO_ON;
30194 + * 0. build session
30195 + * 1. get a proxy connection
30196 + * 2. create the http-request header
30197 + * 3. stream the content to the backend
30198 + * 4. wait for http-response header
30199 + * 5. decode the response + parse the response
30200 + * 6. stream the response-content to the client
30201 + * 7. kill session
30205 + /* a session lives for a single request */
30206 + sess = proxy_session_init();
30208 + con->plugin_ctx[p->id] = sess;
30209 + con->mode = p->id;
30211 + sess->remote_con = con;
30214 + switch (sess->state) {
30215 + case PROXY_STATE_CONNECTING:
30216 + /* this connections is waited 10 seconds to connect to the backend
30217 + * and didn't got a successful connection yet, sending timeout */
30218 + if (srv->cur_ts - con->request_start > 10) {
30219 + con->http_status = 504; /* gateway timeout */
30221 + if (sess->proxy_con) {
30222 + /* if we are waiting for a proxy-connection right now, close it */
30223 + proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30225 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30226 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
30228 + proxy_connection_free(sess->proxy_con);
30230 + sess->proxy_con = NULL;
30233 + return HANDLER_FINISHED;
30236 + /* handle-request-timeout, */
30237 + if (srv->cur_ts - con->request_start > 60) {
30238 + TRACE("request runs longer than 60sec: current state: %d", sess->state);
30243 + /* if the WRITE fails from the start, restart the connection */
30245 + if (sess->proxy_con == NULL) {
30246 + proxy_address *address = NULL;
30247 + if (NULL == (sess->proxy_backend = proxy_get_backend(srv, con, p))) {
30248 + /* no connection pool for this location */
30253 + * ask the balancer for the next address and
30254 + * check the connection pool if we have a connection open
30255 + * for that address
30257 + if (NULL == (address = proxy_backend_balance(srv, con, sess->proxy_backend))) {
30258 + /* we don't have any backends to connect to */
30259 + proxy_request *req;
30261 + /* connection pool is full, queue the request for now */
30262 + req = proxy_request_init();
30263 + req->added_ts = srv->cur_ts;
30266 + TRACE("backlog: all backends are down, putting %s (%d) into the backlog", BUF_STR(con->uri.path), con->sock->fd);
30267 + proxy_backlog_push(p->conf.backlog, req);
30269 + /* no, not really a event,
30270 + * we just want to block the outer loop from stepping forward
30272 + * the trigger will bring this connection back into the game
30274 + return HANDLER_WAIT_FOR_EVENT;
30277 + if (PROXY_CONNECTIONPOOL_FULL == proxy_connection_pool_get_connection(
30278 + sess->proxy_backend->pool,
30280 + &(sess->proxy_con))) {
30281 + proxy_request *req;
30283 + /* connection pool is full, queue the request for now */
30284 + req = proxy_request_init();
30285 + req->added_ts = srv->cur_ts;
30288 + TRACE("backlog: the con-pool is full, putting %s (%d) into the backlog", con->uri.path->ptr, con->sock->fd);
30289 + proxy_backlog_push(p->conf.backlog, req);
30291 + /* no, not really a event,
30292 + * we just want to block the outer loop from stepping forward
30294 + * the trigger will bring this connection back into the game
30296 + return HANDLER_WAIT_FOR_EVENT;
30299 + /* a fresh connection, we need address for it */
30300 + if (sess->proxy_con->state == PROXY_CONNECTION_STATE_CONNECTING) {
30301 + sess->state = PROXY_STATE_UNSET;
30302 + sess->bytes_read = 0;
30304 + /* we are already connected */
30305 + sess->state = PROXY_STATE_CONNECTED;
30307 + /* the connection was idling and using the fdevent_idle-handler
30308 + * switch it back to the normal proxy-event-handler */
30309 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30310 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
30312 + fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
30313 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30317 + switch (proxy_state_engine(srv, con, p, sess)) {
30318 + case HANDLER_WAIT_FOR_EVENT:
30319 + return HANDLER_WAIT_FOR_EVENT;
30320 + case HANDLER_COMEBACK:
30321 + proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30323 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30324 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
30326 + proxy_connection_free(sess->proxy_con);
30328 + sess->proxy_con = NULL;
30329 + /* restart the connection to the backend */
30330 + TRACE("%s", "write failed, restarting request");
30332 + case HANDLER_GO_ON:
30333 + return HANDLER_GO_ON;
30335 + return HANDLER_ERROR;
30339 + /* should not be reached */
30340 + return HANDLER_ERROR;
30344 + * end of the connection to the client
30346 +REQUESTDONE_FUNC(mod_proxy_connection_close_callback) {
30347 + plugin_data *p = p_d;
30349 + if (con->mode != p->id) return HANDLER_GO_ON;
30351 + return HANDLER_GO_ON;
30355 + * end of a request
30357 +CONNECTION_FUNC(mod_proxy_connection_reset) {
30358 + plugin_data *p = p_d;
30359 + proxy_session *sess = con->plugin_ctx[p->id];
30361 + if (con->mode != p->id) return HANDLER_GO_ON;
30363 + if (sess->proxy_con) {
30364 + switch (sess->proxy_con->state) {
30365 + case PROXY_CONNECTION_STATE_CONNECTED:
30366 + sess->proxy_con->state = PROXY_CONNECTION_STATE_IDLE;
30368 + /* ignore events as the FD is idle, we might get a HUP as the remote connection might close */
30369 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30370 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
30372 + fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent_idle, sess->proxy_con);
30373 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30376 + case PROXY_CONNECTION_STATE_CLOSED:
30377 + proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30379 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30380 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
30382 + proxy_connection_free(sess->proxy_con);
30384 + case PROXY_CONNECTION_STATE_IDLE:
30385 + TRACE("%s", "... connection is already back in the pool");
30388 + ERROR("connection is in a unexpected state at close-time: %d", sess->proxy_con->state);
30392 + /* if we have the connection in the backlog, remove it */
30393 + proxy_backlog_remove_connection(p->conf.backlog, con);
30397 + proxy_session_free(sess);
30399 + con->plugin_ctx[p->id] = NULL;
30401 + return HANDLER_GO_ON;
30407 + * cleanup dead connections once a second
30409 + * the idling event-handler can't cleanup connections itself and has to wait until the
30410 + * trigger cleans up
30412 +handler_t mod_proxy_trigger_context(server *srv, plugin_config *p) {
30414 + proxy_request *req;
30416 + for (i = 0; i < p->backends->used; i++) {
30417 + proxy_backend *backend = p->backends->ptr[i];
30418 + proxy_connection_pool *pool = backend->pool;
30419 + proxy_address_pool *address_pool = backend->address_pool;
30421 + for (j = 0; j < pool->used; ) {
30422 + proxy_connection *proxy_con = pool->ptr[j];
30424 + /* remove-con is removing the current con and moves the good connections to the left
30425 + * no need to increment i */
30426 + if (proxy_con->state == PROXY_CONNECTION_STATE_CLOSED) {
30427 + proxy_connection_pool_remove_connection(backend->pool, proxy_con);
30429 + fdevent_event_del(srv->ev, proxy_con->sock);
30430 + fdevent_unregister(srv->ev, proxy_con->sock);
30432 + proxy_connection_free(proxy_con);
30438 + /* active the disabled addresses again */
30439 + for (j = 0; j < address_pool->used; j++) {
30440 + proxy_address *address = address_pool->ptr[j];
30442 + if (address->state != PROXY_ADDRESS_STATE_DISABLED) continue;
30444 + if (srv->cur_ts > address->disabled_until) {
30445 + address->disabled_until = 0;
30446 + address->state = PROXY_ADDRESS_STATE_ACTIVE;
30451 + /* wake up the connections from the backlog */
30452 + while ((req = proxy_backlog_shift(p->backlog))) {
30453 + connection *con = req->con;
30455 + joblist_append(srv, con);
30457 + proxy_request_free(req);
30460 + return HANDLER_GO_ON;
30463 +TRIGGER_FUNC(mod_proxy_trigger) {
30464 + plugin_data *p = p_d;
30467 + for (i = 0; i < srv->config_context->used; i++) {
30468 + mod_proxy_trigger_context(srv, p->config_storage[i]);
30471 + return HANDLER_GO_ON;
30474 +int mod_proxy_core_plugin_init(plugin *p) {
30475 + p->version = LIGHTTPD_VERSION_ID;
30476 + p->name = buffer_init_string("mod_proxy_core");
30478 + p->init = mod_proxy_core_init;
30479 + p->cleanup = mod_proxy_core_free;
30480 + p->set_defaults = mod_proxy_core_set_defaults;
30481 + p->handle_uri_clean = mod_proxy_core_check_extension;
30482 + p->handle_subrequest_start = mod_proxy_core_check_extension;
30483 + p->handle_subrequest = mod_proxy_core_check_extension;
30484 + p->connection_reset = mod_proxy_connection_reset;
30485 + p->handle_connection_close = mod_proxy_connection_close_callback;
30486 + p->handle_trigger = mod_proxy_trigger;
30492 --- ../lighttpd-1.4.11/src/mod_proxy_core.h 1970-01-01 03:00:00.000000000 +0300
30493 +++ lighttpd-1.4.12/src/mod_proxy_core.h 2006-07-18 13:03:40.000000000 +0300
30495 +#ifndef _MOD_PROXY_CORE_H_
30496 +#define _MOD_PROXY_CORE_H_
30498 +#include "buffer.h"
30501 +#define PROXY_BACKEND_CONNECT_PARAMS \
30502 + (server *srv, connection *con, void *p_d)
30504 +#define PROXY_BACKEND_CONNECT_RETVAL handler_t
30506 +#define PROXY_BACKEND_CONNECT(name) \
30507 + PROXY_BACKEND_CONNECT_RETVAL name PROXY_BACKEND_CONNECT_PARAMS
30509 +#define PROXY_BACKEND_CONNECT_PTR(name) \
30510 + PROXY_BACKEND_CONNECT_RETVAL (* name)PROXY_BACKEND_CONNECT_PARAMS
30513 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.c 1970-01-01 03:00:00.000000000 +0300
30514 +++ lighttpd-1.4.12/src/mod_proxy_core_address.c 2006-07-18 13:03:40.000000000 +0300
30516 +#include <stdlib.h>
30517 +#include <string.h>
30520 +#include "sys-socket.h"
30521 +#include "mod_proxy_core_address.h"
30523 +proxy_address *proxy_address_init(void) {
30524 + proxy_address *address;
30526 + address = calloc(1, sizeof(*address));
30528 + address->name = buffer_init();
30533 +void proxy_address_free(proxy_address *address) {
30534 + if (!address) return;
30536 + buffer_free(address->name);
30542 +proxy_address_pool *proxy_address_pool_init(void) {
30543 + proxy_address_pool *address_pool;
30545 + address_pool = calloc(1, sizeof(*address_pool));
30547 + return address_pool;
30550 +void proxy_address_pool_free(proxy_address_pool *address_pool) {
30551 + if (!address_pool) return;
30553 + FOREACH(address_pool, element, proxy_address_free(element))
30555 + free(address_pool);
30558 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address) {
30559 + ARRAY_STATIC_PREPARE_APPEND(address_pool);
30561 + address_pool->ptr[address_pool->used++] = address;
30564 +int proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *name) {
30565 + struct addrinfo *res = NULL, pref, *cur;
30568 + pref.ai_flags = 0;
30569 + pref.ai_family = PF_UNSPEC;
30570 + pref.ai_socktype = SOCK_STREAM;
30571 + pref.ai_protocol = 0;
30572 + pref.ai_addrlen = 0;
30573 + pref.ai_addr = NULL;
30574 + pref.ai_canonname = NULL;
30575 + pref.ai_next = NULL;
30577 + if (0 != (ret = getaddrinfo(name->ptr, "80", &pref, &res))) {
30578 + ERROR("getaddrinfo failed: %s", gai_strerror(ret));
30583 + for (cur = res; cur; cur = cur->ai_next) {
30584 + proxy_address *a = proxy_address_init();
30586 + memcpy(&(a->addr), cur->ai_addr, cur->ai_addrlen);
30588 + a->state = PROXY_ADDRESS_STATE_ACTIVE;
30590 + buffer_copy_string(a->name, inet_ntoa(a->addr.ipv4.sin_addr));
30592 + proxy_address_pool_add(address_pool, a);
30595 + freeaddrinfo(res);
30601 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.h 1970-01-01 03:00:00.000000000 +0300
30602 +++ lighttpd-1.4.12/src/mod_proxy_core_address.h 2006-07-18 13:03:40.000000000 +0300
30604 +#ifndef _MOD_PROXY_CORE_ADDRESS_H_
30605 +#define _MOD_PROXY_CORE_ADDRESS_H_
30608 +#include "buffer.h"
30609 +#include "sys-socket.h"
30610 +#include "array-static.h"
30613 + PROXY_ADDRESS_STATE_UNSET,
30614 + PROXY_ADDRESS_STATE_ACTIVE,
30615 + PROXY_ADDRESS_STATE_DISABLED,
30616 +} proxy_address_state_t;
30621 + buffer *name; /* a inet_ntoa() prepresentation of the address */
30623 + time_t last_used;
30624 + time_t disabled_until;
30626 + proxy_address_state_t state;
30629 +ARRAY_STATIC_DEF(proxy_address_pool, proxy_address, );
30631 +proxy_address_pool *proxy_address_pool_init(void);
30632 +void proxy_address_pool_free(proxy_address_pool *address_pool);
30633 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address);
30634 +int proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *address);
30637 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.c 1970-01-01 03:00:00.000000000 +0300
30638 +++ lighttpd-1.4.12/src/mod_proxy_core_backend.c 2006-07-18 13:03:40.000000000 +0300
30640 +#include <stdlib.h>
30642 +#include "mod_proxy_core_backend.h"
30643 +#include "mod_proxy_core_pool.h"
30644 +#include "mod_proxy_core_address.h"
30646 +proxy_backend *proxy_backend_init(void) {
30647 + proxy_backend *backend;
30649 + backend = calloc(1, sizeof(*backend));
30650 + backend->pool = proxy_connection_pool_init();
30651 + backend->address_pool = proxy_address_pool_init();
30652 + backend->balancer = PROXY_BALANCE_RR;
30657 +void proxy_backend_free(proxy_backend *backend) {
30658 + if (!backend) return;
30660 + proxy_address_pool_free(backend->address_pool);
30661 + proxy_connection_pool_free(backend->pool);
30666 +proxy_backends *proxy_backends_init(void) {
30667 + proxy_backends *backends;
30669 + backends = calloc(1, sizeof(*backends));
30674 +void proxy_backends_free(proxy_backends *backends) {
30675 + FOREACH(backends, element, proxy_backend_free(element))
30680 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend) {
30681 + ARRAY_STATIC_PREPARE_APPEND(backends);
30683 + backends->ptr[backends->used++] = backend;
30685 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.h 1970-01-01 03:00:00.000000000 +0300
30686 +++ lighttpd-1.4.12/src/mod_proxy_core_backend.h 2006-07-18 13:03:40.000000000 +0300
30688 +#ifndef _MOD_PROXY_CORE_BACKEND_H_
30689 +#define _MOD_PROXY_CORE_BACKEND_H_
30691 +#include "array-static.h"
30692 +#include "buffer.h"
30693 +#include "mod_proxy_core_address.h"
30694 +#include "mod_proxy_core_pool.h"
30695 +#include "sys-socket.h"
30698 + * a single DNS name might explode to several IP addresses
30701 + * - http://foo.bar/suburl/
30702 + * - https://foo.bar/suburl/
30703 + * - unix:/tmp/socket
30704 + * - tcp://foobar:1025/
30711 + * request-url-rewrite
30712 + * response-url-rewrite
30715 + PROXY_BALANCE_UNSET,
30716 + PROXY_BALANCE_FAIR,
30717 + PROXY_BALANCE_HASH,
30719 +} proxy_balance_t;
30724 + proxy_connection_pool *pool; /* pool of active connections */
30725 + int use_keepalive;
30727 + proxy_address_pool *address_pool; /* possible destination-addresses, disabling is done here */
30728 + proxy_balance_t balancer; /* how to choose a address from the address-pool */
30731 +ARRAY_STATIC_DEF(proxy_backends, proxy_backend, );
30733 +proxy_backend *proxy_backend_init(void);
30734 +void proxy_backend_free(proxy_backend *backend);
30736 +proxy_backends *proxy_backends_init(void);
30737 +void proxy_backends_free(proxy_backends *backends);
30738 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend);
30742 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.c 1970-01-01 03:00:00.000000000 +0300
30743 +++ lighttpd-1.4.12/src/mod_proxy_core_backlog.c 2006-07-18 13:03:40.000000000 +0300
30745 +#include <stdlib.h>
30747 +#include "mod_proxy_core_backlog.h"
30748 +#include "array-static.h"
30750 +proxy_backlog *proxy_backlog_init(void) {
30751 + STRUCT_INIT(proxy_backlog, backlog);
30756 +void proxy_backlog_free(proxy_backlog *backlog) {
30757 + if (!backlog) return;
30762 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req) {
30763 + /* first entry */
30764 + if (NULL == backlog->first) {
30765 + backlog->first = backlog->last = req;
30767 + backlog->last->next = req;
30768 + backlog->last = req;
30770 + backlog->length++;
30776 + * remove the first element from the backlog
30778 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog) {
30779 + proxy_request *req = NULL;
30781 + if (!backlog->first) return req;
30783 + backlog->length--;
30785 + req = backlog->first;
30787 + backlog->first = req->next;
30789 + /* the backlog is empty */
30790 + if (backlog->first == NULL) backlog->last = NULL;
30795 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con) {
30796 + proxy_request *req = NULL;
30798 + if (!backlog->first) return -1;
30799 + if (!con) return -1;
30801 + /* the first element is what we look for */
30802 + if (backlog->first->con == con) {
30803 + req = backlog->first;
30805 + backlog->first = req->next;
30806 + if (backlog->first == NULL) backlog->last = NULL;
30808 + backlog->length--;
30810 + proxy_request_free(req);
30816 + for (req = backlog->first; req && req->next; req = req->next) {
30817 + proxy_request *cur;
30819 + if (req->next->con != con) continue;
30821 + backlog->length--;
30822 + /* the next node is our searched connection */
30825 + req->next = cur->next;
30827 + /* the next node is the last one, make the current the new last */
30828 + if (cur == backlog->last) {
30829 + backlog->last = req;
30831 + cur->next = NULL;
30833 + proxy_request_free(req);
30841 +proxy_request *proxy_request_init(void) {
30842 + STRUCT_INIT(proxy_request, request);
30847 +void proxy_request_free(proxy_request *request) {
30848 + if (!request) return;
30854 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.h 1970-01-01 03:00:00.000000000 +0300
30855 +++ lighttpd-1.4.12/src/mod_proxy_core_backlog.h 2006-07-18 13:03:40.000000000 +0300
30857 +#ifndef _MOD_PROXY_CORE_BACKLOG_H_
30858 +#define _MOD_PROXY_CORE_BACKLOG_H_
30860 +#include <sys/types.h>
30861 +#include <sys/time.h>
30863 +typedef struct _proxy_request {
30864 + void *con; /* a pointer to the client-connection, (type: connection) */
30866 + time_t added_ts; /* when was the entry added (for timeout handling) */
30868 + struct _proxy_request *next;
30872 + * a we can't get a connection from the pool, queue the request in the
30873 + * request queue (FIFO)
30875 + * - the queue is infinite
30876 + * - entries are removed after a timeout (status 504)
30879 + proxy_request *first; /* pull() does q->first = q->first->next */
30880 + proxy_request *last; /* push() does q->last = r */
30885 +proxy_backlog *proxy_backlog_init(void);
30886 +void proxy_backlog_free(proxy_backlog *backlog);
30889 + * append a request to the end
30891 + * @return 0 in success, -1 if full
30893 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req);
30896 + * remove the first request from the backlog
30898 + * @return NULL if backlog is empty, the request otherwise
30900 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog);
30902 + * remove the request with the connection 'con' from the backlog
30904 + * @return -1 if not found, 0 otherwise
30906 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con);
30908 +proxy_request *proxy_request_init(void);
30909 +void proxy_request_free(proxy_request *req);
30913 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.c 1970-01-01 03:00:00.000000000 +0300
30914 +++ lighttpd-1.4.12/src/mod_proxy_core_pool.c 2006-07-18 13:03:40.000000000 +0300
30917 +#include <stdlib.h>
30919 +#include "array-static.h"
30920 +#include "sys-files.h"
30922 +#include "mod_proxy_core_pool.h"
30924 +proxy_connection * proxy_connection_init(void) {
30925 + proxy_connection *con;
30927 + con = calloc(1, sizeof(*con));
30929 + con->sock = iosocket_init();
30934 +void proxy_connection_free(proxy_connection *con) {
30935 + if (!con) return;
30937 + iosocket_free(con->sock);
30942 +proxy_connection_pool *proxy_connection_pool_init(void) {
30943 + proxy_connection_pool *pool;
30945 + pool = calloc(1, sizeof(*pool));
30947 + /* default: max parallel connections to the backend
30949 + * this should match max-procs if we manage the procs ourself
30952 + pool->max_size = 8;
30957 +void proxy_connection_pool_free(proxy_connection_pool *pool) {
30960 + if (!pool) return;
30962 + for (i = 0; i < pool->used; i++) {
30963 + proxy_connection_free(pool->ptr[i]);
30966 + if (pool->size) free(pool->ptr);
30971 +void proxy_connection_pool_add_connection(proxy_connection_pool *pool, proxy_connection *c) {
30972 + ARRAY_STATIC_PREPARE_APPEND(pool);
30974 + pool->ptr[pool->used++] = c;
30977 + * remove the connection from the pool
30979 + * usually called on conn-shutdown
30981 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c) {
30984 + if (pool->used == 0) return -1; /* empty */
30986 + for (i = 0; i < pool->used; i++) {
30987 + if (pool->ptr[i] == c) {
30992 + if (i == pool->used) return -1; /* not found */
30995 + * move all elements one to the left
30997 + * if the last element is going to be removed, skip the loop
30999 + for (; i < pool->used - 1; i++) {
31000 + pool->ptr[i] = pool->ptr[i + 1];
31008 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon) {
31009 + proxy_connection *proxy_con = NULL;
31012 + /* search for a idling proxy connection with the given address */
31013 + for (i = 0; i < pool->used; i++) {
31014 + proxy_con = pool->ptr[i];
31016 + if (proxy_con->address == address &&
31017 + proxy_con->state == PROXY_CONNECTION_STATE_IDLE) {
31022 + if (i == pool->used) {
31023 + /* no idling connection found */
31025 + if (pool->used == pool->max_size) return PROXY_CONNECTIONPOOL_FULL;
31027 + proxy_con = proxy_connection_init();
31029 + proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
31030 + proxy_con->address = address;
31032 + proxy_connection_pool_add_connection(pool, proxy_con);
31034 + proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
31037 + *rcon = proxy_con;
31039 + return PROXY_CONNECTIONPOOL_GOT_CONNECTION;
31043 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.h 1970-01-01 03:00:00.000000000 +0300
31044 +++ lighttpd-1.4.12/src/mod_proxy_core_pool.h 2006-07-18 13:03:40.000000000 +0300
31046 +#ifndef _MOD_PROXY_CORE_POOL_H_
31047 +#define _MOD_PROXY_CORE_POOL_H_
31049 +#include <sys/time.h>
31051 +#include "iosocket.h"
31052 +#include "array-static.h"
31053 +#include "mod_proxy_core_address.h"
31056 + PROXY_CONNECTION_STATE_UNSET,
31057 + PROXY_CONNECTION_STATE_CONNECTING,
31058 + PROXY_CONNECTION_STATE_CONNECTED,
31059 + PROXY_CONNECTION_STATE_IDLE,
31060 + PROXY_CONNECTION_STATE_CLOSED,
31061 +} proxy_connection_state_t;
31064 + * a connection to a proxy backend
31066 + * the connection is independent of the incoming request to allow keep-alive
31071 + time_t last_read; /* timeout handling for keep-alive connections */
31072 + time_t last_write;
31074 + proxy_address *address; /* the struct sock_addr for the sock */
31076 + proxy_connection_state_t state;
31077 +} proxy_connection;
31079 +ARRAY_STATIC_DEF(proxy_connection_pool, proxy_connection, size_t max_size;);
31082 + PROXY_CONNECTIONPOOL_UNSET,
31083 + PROXY_CONNECTIONPOOL_FULL,
31084 + PROXY_CONNECTIONPOOL_GOT_CONNECTION,
31085 +} proxy_connection_pool_t;
31087 +proxy_connection_pool *proxy_connection_pool_init(void);
31088 +void proxy_connection_pool_free(proxy_connection_pool *pool);
31090 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon);
31091 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c);
31093 +proxy_connection * proxy_connection_init(void);
31094 +void proxy_connection_free(proxy_connection *pool);
31098 --- ../lighttpd-1.4.11/src/mod_proxy_core_rewrites.c 1970-01-01 03:00:00.000000000 +0300
31099 +++ lighttpd-1.4.12/src/mod_proxy_core_rewrites.c 2006-07-18 17:34:32.000000000 +0300
31101 +#include <stdlib.h>
31102 +#include <string.h>
31104 +#include "mod_proxy_core_rewrites.h"
31107 +proxy_rewrite *proxy_rewrite_init(void) {
31108 + STRUCT_INIT(proxy_rewrite, rewrite);
31110 + rewrite->header = buffer_init();
31111 + rewrite->match = buffer_init();
31112 + rewrite->replace = buffer_init();
31117 +void proxy_rewrite_free(proxy_rewrite *rewrite) {
31118 + if (!rewrite) return;
31120 + if (rewrite->regex) pcre_free(rewrite->regex);
31122 + buffer_free(rewrite->header);
31123 + buffer_free(rewrite->match);
31124 + buffer_free(rewrite->replace);
31129 +int proxy_rewrite_set_regex(proxy_rewrite *rewrite, buffer *regex) {
31130 + const char *errptr;
31133 + if (NULL == (rewrite->regex = pcre_compile(BUF_STR(regex),
31134 + 0, &errptr, &erroff, NULL))) {
31136 + TRACE("regex compilation for %s failed at %s", BUF_STR(regex), errptr);
31145 +proxy_rewrites *proxy_rewrites_init(void) {
31146 + STRUCT_INIT(proxy_rewrites, rewrites);
31151 +void proxy_rewrites_add(proxy_rewrites *rewrites, proxy_rewrite *rewrite) {
31152 + ARRAY_STATIC_PREPARE_APPEND(rewrites);
31154 + rewrites->ptr[rewrites->used++] = rewrite;
31157 +void proxy_rewrites_free(proxy_rewrites *rewrites) {
31158 + if (!rewrites) return;
31165 --- ../lighttpd-1.4.11/src/mod_proxy_core_rewrites.h 1970-01-01 03:00:00.000000000 +0300
31166 +++ lighttpd-1.4.12/src/mod_proxy_core_rewrites.h 2006-07-18 17:34:32.000000000 +0300
31168 +#ifndef _MOD_PROXY_CORE_REWRITES_H_
31169 +#define _MOD_PROXY_CORE_REWRITES_H_
31172 +#include "array-static.h"
31173 +#include "buffer.h"
31178 + pcre *regex; /* regex compiled from the <match> */
31184 +ARRAY_STATIC_DEF(proxy_rewrites, proxy_rewrite,);
31186 +proxy_rewrite *proxy_rewrite_init(void);
31187 +void proxy_rewrite_free(proxy_rewrite *rewrite);
31188 +int proxy_rewrite_set_regex(proxy_rewrite *rewrite, buffer *regex);
31190 +proxy_rewrites *proxy_rewrites_init(void);
31191 +void proxy_rewrites_add(proxy_rewrites *rewrites, proxy_rewrite *rewrite);
31192 +void proxy_rewrites_free(proxy_rewrites *rewrites);
31196 --- ../lighttpd-1.4.11/src/mod_redirect.c 2006-02-08 15:38:06.000000000 +0200
31197 +++ lighttpd-1.4.12/src/mod_redirect.c 2006-07-16 00:26:04.000000000 +0300
31198 @@ -22,35 +22,35 @@
31204 plugin_config **config_storage;
31206 - plugin_config conf;
31208 + plugin_config conf;
31211 INIT_FUNC(mod_redirect_init) {
31215 p = calloc(1, sizeof(*p));
31218 p->match_buf = buffer_init();
31219 p->location = buffer_init();
31225 FREE_FUNC(mod_redirect_free) {
31226 plugin_data *p = p_d;
31229 if (!p) return HANDLER_GO_ON;
31231 if (p->config_storage) {
31233 for (i = 0; i < srv->config_context->used; i++) {
31234 plugin_config *s = p->config_storage[i];
31237 pcre_keyvalue_buffer_free(s->redirect);
31242 free(p->config_storage);
31245 buffer_free(p->match_buf);
31246 buffer_free(p->location);
31252 return HANDLER_GO_ON;
31255 @@ -69,195 +69,137 @@
31256 plugin_data *p = p_d;
31260 - config_values_t cv[] = {
31262 + config_values_t cv[] = {
31263 { "url.redirect", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
31264 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
31268 if (!p) return HANDLER_ERROR;
31272 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
31275 for (i = 0; i < srv->config_context->used; i++) {
31279 data_array *da = (data_array *)du;
31282 s = calloc(1, sizeof(plugin_config));
31283 s->redirect = pcre_keyvalue_buffer_init();
31286 cv[0].destination = s->redirect;
31289 p->config_storage[i] = s;
31290 ca = ((data_config *)srv->config_context->data[i])->value;
31293 if (0 != config_insert_values_global(srv, ca, cv)) {
31294 return HANDLER_ERROR;
31298 if (NULL == (du = array_get_element(ca, "url.redirect"))) {
31299 /* no url.redirect defined */
31304 if (du->type != TYPE_ARRAY) {
31305 - log_error_write(srv, __FILE__, __LINE__, "sss",
31306 + log_error_write(srv, __FILE__, __LINE__, "sss",
31307 "unexpected type for key: ", "url.redirect", "array of strings");
31310 return HANDLER_ERROR;
31314 da = (data_array *)du;
31317 for (j = 0; j < da->value->used; j++) {
31318 if (da->value->data[j]->type != TYPE_STRING) {
31319 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
31320 - "unexpected type for key: ",
31322 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
31323 + "unexpected type for key: ",
31325 "[", da->value->data[j]->key, "](string)");
31328 return HANDLER_ERROR;
31331 - if (0 != pcre_keyvalue_buffer_append(s->redirect,
31333 + if (0 != pcre_keyvalue_buffer_append(s->redirect,
31334 ((data_string *)(da->value->data[j]))->key->ptr,
31335 ((data_string *)(da->value->data[j]))->value->ptr)) {
31337 - log_error_write(srv, __FILE__, __LINE__, "sb",
31339 + log_error_write(srv, __FILE__, __LINE__, "sb",
31340 "pcre-compile failed for", da->value->data[j]->key);
31346 return HANDLER_GO_ON;
31349 static int mod_redirect_patch_connection(server *srv, connection *con, plugin_data *p) {
31351 plugin_config *s = p->config_storage[0];
31354 p->conf.redirect = s->redirect;
31357 /* skip the first, the global context */
31358 for (i = 1; i < srv->config_context->used; i++) {
31359 data_config *dc = (data_config *)srv->config_context->data[i];
31360 s = p->config_storage[i];
31363 /* condition didn't match */
31364 if (!config_check_cond(srv, con, dc)) continue;
31368 for (j = 0; j < dc->value->used; j++) {
31369 data_unset *du = dc->value->data[j];
31372 if (0 == strcmp(du->key->ptr, "url.redirect")) {
31373 p->conf.redirect = s->redirect;
31374 p->conf.context = dc;
31383 static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_data) {
31385 plugin_data *p = p_data;
31394 * e.g. redirect /base/ to /index.php?section=base
31400 mod_redirect_patch_connection(srv, con, p);
31403 buffer_copy_string_buffer(p->match_buf, con->request.uri);
31405 - for (i = 0; i < p->conf.redirect->used; i++) {
31407 - pcre_extra *extra;
31408 - const char *pattern;
31409 - size_t pattern_len;
31411 - pcre_keyvalue *kv = p->conf.redirect->kv[i];
31416 - extra = kv->key_extra;
31417 - pattern = kv->value->ptr;
31418 - pattern_len = kv->value->used - 1;
31420 - if ((n = pcre_exec(match, extra, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
31421 - if (n != PCRE_ERROR_NOMATCH) {
31422 - log_error_write(srv, __FILE__, __LINE__, "sd",
31423 - "execution error while matching: ", n);
31424 - return HANDLER_ERROR;
31427 - const char **list;
31428 - size_t start, end;
31432 - pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
31434 - /* search for $[0-9] */
31436 - buffer_reset(p->location);
31438 - start = 0; end = pattern_len;
31439 - for (k = 0; k < pattern_len; k++) {
31440 - if ((pattern[k] == '$' || pattern[k] == '%') &&
31441 - isdigit((unsigned char)pattern[k + 1])) {
31444 - size_t num = pattern[k + 1] - '0';
31448 - buffer_append_string_len(p->location, pattern + start, end - start);
31450 - if (pattern[k] == '$') {
31451 - /* n is always > 0 */
31452 - if (num < (size_t)n) {
31453 - buffer_append_string(p->location, list[num]);
31456 - config_append_cond_match_buffer(con, p->conf.context, p->location, num);
31464 - buffer_append_string_len(p->location, pattern + start, pattern_len - start);
31468 - response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
31470 - con->http_status = 301;
31471 - con->file_finished = 1;
31473 - return HANDLER_FINISHED;
31475 + i = config_exec_pcre_keyvalue_buffer(con, p->conf.redirect, p->conf.context, p->match_buf, p->location);
31478 + response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
31480 + con->http_status = 301;
31481 + con->file_finished = 1;
31483 + return HANDLER_FINISHED;
31485 + else if (i != PCRE_ERROR_NOMATCH) {
31486 + log_error_write(srv, __FILE__, __LINE__, "s",
31487 + "execution error while matching", i);
31499 return HANDLER_GO_ON;
31502 @@ -265,13 +207,13 @@
31503 int mod_redirect_plugin_init(plugin *p) {
31504 p->version = LIGHTTPD_VERSION_ID;
31505 p->name = buffer_init_string("redirect");
31508 p->init = mod_redirect_init;
31509 p->handle_uri_clean = mod_redirect_uri_handler;
31510 p->set_defaults = mod_redirect_set_defaults;
31511 p->cleanup = mod_redirect_free;
31519 --- ../lighttpd-1.4.11/src/mod_rewrite.c 2005-09-29 20:59:10.000000000 +0300
31520 +++ lighttpd-1.4.12/src/mod_rewrite.c 2006-07-16 00:26:03.000000000 +0300
31525 -#ifdef HAVE_PCRE_H
31535 - rewrite_rule **ptr;
31539 -} rewrite_rule_buffer;
31542 - rewrite_rule_buffer *rewrite;
31543 + pcre_keyvalue_buffer *rewrite;
31545 data_config *context; /* to which apply me */
31548 @@ -42,20 +26,20 @@
31554 plugin_config **config_storage;
31556 - plugin_config conf;
31558 + plugin_config conf;
31561 static handler_ctx * handler_ctx_init() {
31562 handler_ctx * hctx;
31565 hctx = calloc(1, sizeof(*hctx));
31568 hctx->state = REWRITE_STATE_UNSET;
31575 @@ -63,207 +47,136 @@
31579 -rewrite_rule_buffer *rewrite_rule_buffer_init(void) {
31580 - rewrite_rule_buffer *kvb;
31582 - kvb = calloc(1, sizeof(*kvb));
31587 -int rewrite_rule_buffer_append(rewrite_rule_buffer *kvb, buffer *key, buffer *value, int once) {
31588 -#ifdef HAVE_PCRE_H
31590 - const char *errptr;
31593 - if (!key) return -1;
31595 - if (kvb->size == 0) {
31599 - kvb->ptr = malloc(kvb->size * sizeof(*kvb->ptr));
31601 - for(i = 0; i < kvb->size; i++) {
31602 - kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
31604 - } else if (kvb->used == kvb->size) {
31607 - kvb->ptr = realloc(kvb->ptr, kvb->size * sizeof(*kvb->ptr));
31609 - for(i = kvb->used; i < kvb->size; i++) {
31610 - kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
31614 - if (NULL == (kvb->ptr[kvb->used]->key = pcre_compile(key->ptr,
31615 - 0, &errptr, &erroff, NULL))) {
31620 - kvb->ptr[kvb->used]->value = buffer_init();
31621 - buffer_copy_string_buffer(kvb->ptr[kvb->used]->value, value);
31622 - kvb->ptr[kvb->used]->once = once;
31637 -void rewrite_rule_buffer_free(rewrite_rule_buffer *kvb) {
31638 -#ifdef HAVE_PCRE_H
31641 - for (i = 0; i < kvb->size; i++) {
31642 - if (kvb->ptr[i]->key) pcre_free(kvb->ptr[i]->key);
31643 - if (kvb->ptr[i]->value) buffer_free(kvb->ptr[i]->value);
31644 - free(kvb->ptr[i]);
31647 - if (kvb->ptr) free(kvb->ptr);
31654 INIT_FUNC(mod_rewrite_init) {
31658 p = calloc(1, sizeof(*p));
31661 p->match_buf = buffer_init();
31667 FREE_FUNC(mod_rewrite_free) {
31668 plugin_data *p = p_d;
31673 if (!p) return HANDLER_GO_ON;
31676 buffer_free(p->match_buf);
31677 if (p->config_storage) {
31679 for (i = 0; i < srv->config_context->used; i++) {
31680 plugin_config *s = p->config_storage[i];
31681 - rewrite_rule_buffer_free(s->rewrite);
31683 + pcre_keyvalue_buffer_free(s->rewrite);
31684 + buffer_free(s->once);
31688 free(p->config_storage);
31695 return HANDLER_GO_ON;
31698 static int parse_config_entry(server *srv, plugin_config *s, array *ca, const char *option, int once) {
31702 if (NULL != (du = array_get_element(ca, option))) {
31703 data_array *da = (data_array *)du;
31707 if (du->type != TYPE_ARRAY) {
31708 - log_error_write(srv, __FILE__, __LINE__, "sss",
31709 + log_error_write(srv, __FILE__, __LINE__, "sss",
31710 "unexpected type for key: ", option, "array of strings");
31713 return HANDLER_ERROR;
31717 da = (data_array *)du;
31720 for (j = 0; j < da->value->used; j++) {
31721 if (da->value->data[j]->type != TYPE_STRING) {
31722 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
31723 - "unexpected type for key: ",
31725 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
31726 + "unexpected type for key: ",
31728 "[", da->value->data[j]->key, "](string)");
31731 return HANDLER_ERROR;
31734 - if (0 != rewrite_rule_buffer_append(s->rewrite,
31735 - ((data_string *)(da->value->data[j]))->key,
31736 - ((data_string *)(da->value->data[j]))->value,
31739 + if (0 != pcre_keyvalue_buffer_append(s->rewrite,
31740 + ((data_string *)(da->value->data[j]))->key->ptr,
31741 + ((data_string *)(da->value->data[j]))->value->ptr)) {
31743 - log_error_write(srv, __FILE__, __LINE__, "sb",
31744 + log_error_write(srv, __FILE__, __LINE__, "sb",
31745 "pcre-compile failed for", da->value->data[j]->key);
31747 - log_error_write(srv, __FILE__, __LINE__, "s",
31748 + log_error_write(srv, __FILE__, __LINE__, "s",
31749 "pcre support is missing, please install libpcre and the headers");
31754 + buffer_append_string_len(s->once, CONST_STR_LEN("1"));
31756 + buffer_append_string_len(s->once, CONST_STR_LEN("0"));
31765 SETDEFAULTS_FUNC(mod_rewrite_set_defaults) {
31766 plugin_data *p = p_d;
31769 - config_values_t cv[] = {
31771 + config_values_t cv[] = {
31772 { "url.rewrite-repeat", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
31773 { "url.rewrite-once", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
31775 - /* old names, still supported
31778 + /* old names, still supported
31780 * url.rewrite remapped to url.rewrite-once
31781 * url.rewrite-final is url.rewrite-once
31785 { "url.rewrite", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
31786 { "url.rewrite-final", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
31787 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
31791 if (!p) return HANDLER_ERROR;
31795 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
31798 for (i = 0; i < srv->config_context->used; i++) {
31803 s = calloc(1, sizeof(plugin_config));
31804 - s->rewrite = rewrite_rule_buffer_init();
31806 - cv[0].destination = s->rewrite;
31807 - cv[1].destination = s->rewrite;
31808 - cv[2].destination = s->rewrite;
31810 + s->rewrite = pcre_keyvalue_buffer_init();
31811 + s->once = buffer_init();
31813 p->config_storage[i] = s;
31814 ca = ((data_config *)srv->config_context->data[i])->value;
31817 if (0 != config_insert_values_global(srv, ca, cv)) {
31818 return HANDLER_ERROR;
31822 parse_config_entry(srv, s, ca, "url.rewrite-once", 1);
31823 parse_config_entry(srv, s, ca, "url.rewrite-final", 1);
31824 parse_config_entry(srv, s, ca, "url.rewrite", 1);
31825 parse_config_entry(srv, s, ca, "url.rewrite-repeat", 0);
31829 return HANDLER_GO_ON;
31832 @@ -271,157 +184,107 @@
31834 plugin_config *s = p->config_storage[0];
31835 p->conf.rewrite = s->rewrite;
31837 + p->conf.once = s->once;
31839 /* skip the first, the global context */
31840 for (i = 1; i < srv->config_context->used; i++) {
31841 data_config *dc = (data_config *)srv->config_context->data[i];
31842 s = p->config_storage[i];
31845 if (COMP_HTTP_URL == dc->comp) continue;
31848 /* condition didn't match */
31849 if (!config_check_cond(srv, con, dc)) continue;
31853 for (j = 0; j < dc->value->used; j++) {
31854 data_unset *du = dc->value->data[j];
31857 if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite"))) {
31858 p->conf.rewrite = s->rewrite;
31859 + p->conf.once = s->once;
31860 p->conf.context = dc;
31861 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-once"))) {
31862 p->conf.rewrite = s->rewrite;
31863 + p->conf.once = s->once;
31864 p->conf.context = dc;
31865 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-repeat"))) {
31866 p->conf.rewrite = s->rewrite;
31867 + p->conf.once = s->once;
31868 p->conf.context = dc;
31869 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-final"))) {
31870 p->conf.rewrite = s->rewrite;
31871 + p->conf.once = s->once;
31872 p->conf.context = dc;
31881 URIHANDLER_FUNC(mod_rewrite_con_reset) {
31882 plugin_data *p = p_d;
31888 if (con->plugin_ctx[p->id]) {
31889 handler_ctx_free(con->plugin_ctx[p->id]);
31890 con->plugin_ctx[p->id] = NULL;
31894 return HANDLER_GO_ON;
31897 URIHANDLER_FUNC(mod_rewrite_uri_handler) {
31899 plugin_data *p = p_d;
31909 * e.g. rewrite /base/ to /index.php?section=base
31915 if (con->plugin_ctx[p->id]) {
31916 hctx = con->plugin_ctx[p->id];
31919 if (hctx->loops++ > 100) {
31920 - log_error_write(srv, __FILE__, __LINE__, "s",
31921 + log_error_write(srv, __FILE__, __LINE__, "s",
31922 "ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request, perhaps you want to use url.rewrite-once instead of url.rewrite-repeat");
31925 return HANDLER_ERROR;
31929 if (hctx->state == REWRITE_STATE_FINISHED) return HANDLER_GO_ON;
31933 mod_rewrite_patch_connection(srv, con, p);
31935 if (!p->conf.rewrite) return HANDLER_GO_ON;
31938 buffer_copy_string_buffer(p->match_buf, con->request.uri);
31940 - for (i = 0; i < p->conf.rewrite->used; i++) {
31942 - const char *pattern;
31943 - size_t pattern_len;
31945 - rewrite_rule *rule = p->conf.rewrite->ptr[i];
31949 - match = rule->key;
31950 - pattern = rule->value->ptr;
31951 - pattern_len = rule->value->used - 1;
31953 - if ((n = pcre_exec(match, NULL, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
31954 - if (n != PCRE_ERROR_NOMATCH) {
31955 - log_error_write(srv, __FILE__, __LINE__, "sd",
31956 - "execution error while matching: ", n);
31957 - return HANDLER_ERROR;
31960 - const char **list;
31961 - size_t start, end;
31965 - pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
31967 - /* search for $[0-9] */
31969 - buffer_reset(con->request.uri);
31971 - start = 0; end = pattern_len;
31972 - for (k = 0; k < pattern_len; k++) {
31973 - if ((pattern[k] == '$' || pattern[k] == '%') &&
31974 - isdigit((unsigned char)pattern[k + 1])) {
31977 - size_t num = pattern[k + 1] - '0';
31981 - buffer_append_string_len(con->request.uri, pattern + start, end - start);
31983 - if (pattern[k] == '$') {
31984 - /* n is always > 0 */
31985 - if (num < (size_t)n) {
31986 - buffer_append_string(con->request.uri, list[num]);
31989 - config_append_cond_match_buffer(con, p->conf.context, con->request.uri, num);
31997 - buffer_append_string_len(con->request.uri, pattern + start, pattern_len - start);
32001 - hctx = handler_ctx_init();
32003 - con->plugin_ctx[p->id] = hctx;
32005 - if (rule->once) hctx->state = REWRITE_STATE_FINISHED;
32007 - return HANDLER_COMEBACK;
32009 + i = config_exec_pcre_keyvalue_buffer(con, p->conf.rewrite, p->conf.context, p->match_buf, con->request.uri);
32012 + hctx = handler_ctx_init();
32014 + con->plugin_ctx[p->id] = hctx;
32016 + if (p->conf.once->ptr[i] == '1')
32017 + hctx->state = REWRITE_STATE_FINISHED;
32019 + return HANDLER_COMEBACK;
32021 + else if (i != PCRE_ERROR_NOMATCH) {
32022 + log_error_write(srv, __FILE__, __LINE__, "s",
32023 + "execution error while matching", i);
32031 @@ -434,17 +297,17 @@
32032 int mod_rewrite_plugin_init(plugin *p) {
32033 p->version = LIGHTTPD_VERSION_ID;
32034 p->name = buffer_init_string("rewrite");
32037 p->init = mod_rewrite_init;
32038 /* it has to stay _raw as we are matching on uri + querystring
32042 p->handle_uri_raw = mod_rewrite_uri_handler;
32043 p->set_defaults = mod_rewrite_set_defaults;
32044 p->cleanup = mod_rewrite_free;
32045 p->connection_reset = mod_rewrite_con_reset;
32053 --- ../lighttpd-1.4.11/src/mod_rrdtool.c 2005-08-22 01:52:24.000000000 +0300
32054 +++ lighttpd-1.4.12/src/mod_rrdtool.c 2006-07-18 13:03:40.000000000 +0300
32056 #include <stdlib.h>
32058 #include <string.h>
32059 -#include <unistd.h>
32063 @@ -20,10 +19,14 @@
32064 /* no need for waitpid if we don't have fork */
32065 #include <sys/wait.h>
32068 +#include "sys-files.h"
32069 +#include "sys-process.h"
32072 buffer *path_rrdtool_bin;
32076 double requests, *requests_ptr;
32077 double bytes_written, *bytes_written_ptr;
32078 double bytes_read, *bytes_read_ptr;
32079 @@ -31,84 +34,84 @@
32089 int read_fd, write_fd;
32093 int rrdtool_running;
32096 plugin_config **config_storage;
32097 plugin_config conf;
32100 INIT_FUNC(mod_rrd_init) {
32104 p = calloc(1, sizeof(*p));
32107 p->resp = buffer_init();
32108 p->cmd = buffer_init();
32114 FREE_FUNC(mod_rrd_free) {
32115 plugin_data *p = p_d;
32119 if (!p) return HANDLER_GO_ON;
32122 if (p->config_storage) {
32123 for (i = 0; i < srv->config_context->used; i++) {
32124 plugin_config *s = p->config_storage[i];
32127 buffer_free(s->path_rrdtool_bin);
32128 buffer_free(s->path_rrd);
32134 buffer_free(p->cmd);
32135 buffer_free(p->resp);
32138 free(p->config_storage);
32141 if (p->rrdtool_pid) {
32144 close(p->write_fd);
32147 /* collect status */
32148 waitpid(p->rrdtool_pid, &status, 0);
32156 return HANDLER_GO_ON;
32159 int mod_rrd_create_pipe(server *srv, plugin_data *p) {
32163 int to_rrdtool_fds[2];
32164 int from_rrdtool_fds[2];
32167 if (pipe(to_rrdtool_fds)) {
32168 - log_error_write(srv, __FILE__, __LINE__, "ss",
32169 + log_error_write(srv, __FILE__, __LINE__, "ss",
32170 "pipe failed: ", strerror(errno));
32175 if (pipe(from_rrdtool_fds)) {
32176 - log_error_write(srv, __FILE__, __LINE__, "ss",
32177 + log_error_write(srv, __FILE__, __LINE__, "ss",
32178 "pipe failed: ", strerror(errno));
32184 switch (pid = fork()) {
32186 @@ -117,33 +120,28 @@
32192 /* move stdout to from_rrdtool_fd[1] */
32193 close(STDOUT_FILENO);
32194 dup2(from_rrdtool_fds[1], STDOUT_FILENO);
32195 close(from_rrdtool_fds[1]);
32197 close(from_rrdtool_fds[0]);
32200 /* move the stdin to to_rrdtool_fd[0] */
32201 close(STDIN_FILENO);
32202 dup2(to_rrdtool_fds[0], STDIN_FILENO);
32203 close(to_rrdtool_fds[0]);
32205 close(to_rrdtool_fds[1]);
32208 close(STDERR_FILENO);
32210 - if (srv->errorlog_mode == ERRORLOG_FILE) {
32211 - dup2(srv->errorlog_fd, STDERR_FILENO);
32212 - close(srv->errorlog_fd);
32218 args = malloc(sizeof(*args) * argc);
32222 args[i++] = p->conf.path_rrdtool_bin->ptr;
32225 @@ -152,12 +150,12 @@
32226 for (i = 3; i < 256; i++) {
32232 execv(args[0], args);
32235 log_error_write(srv, __FILE__, __LINE__, "sss", "spawing rrdtool failed: ", strerror(errno), args[0]);
32241 @@ -168,19 +166,19 @@
32247 close(from_rrdtool_fds[1]);
32248 close(to_rrdtool_fds[0]);
32251 /* register PID and wait for them asyncronously */
32252 p->write_fd = to_rrdtool_fds[1];
32253 p->read_fd = from_rrdtool_fds[0];
32254 p->rrdtool_pid = pid;
32265 @@ -189,19 +187,19 @@
32267 static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) {
32271 /* check if DB already exists */
32272 if (0 == stat(s->path_rrd->ptr, &st)) {
32273 /* check if it is plain file */
32274 if (!S_ISREG(st.st_mode)) {
32275 - log_error_write(srv, __FILE__, __LINE__, "sb",
32276 + log_error_write(srv, __FILE__, __LINE__, "sb",
32277 "not a regular file:", s->path_rrd);
32278 return HANDLER_ERROR;
32282 /* create a new one */
32285 BUFFER_COPY_STRING_CONST(p->cmd, "create ");
32286 buffer_append_string_buffer(p->cmd, s->path_rrd);
32287 buffer_append_string(p->cmd, " --step 60 ");
32288 @@ -220,158 +218,155 @@
32289 buffer_append_string(p->cmd, "RRA:MIN:0.5:6:700 ");
32290 buffer_append_string(p->cmd, "RRA:MIN:0.5:24:775 ");
32291 buffer_append_string(p->cmd, "RRA:MIN:0.5:288:797\n");
32294 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
32295 - log_error_write(srv, __FILE__, __LINE__, "ss",
32296 + log_error_write(srv, __FILE__, __LINE__, "ss",
32297 "rrdtool-write: failed", strerror(errno));
32300 return HANDLER_ERROR;
32304 buffer_prepare_copy(p->resp, 4096);
32305 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
32306 - log_error_write(srv, __FILE__, __LINE__, "ss",
32307 + log_error_write(srv, __FILE__, __LINE__, "ss",
32308 "rrdtool-read: failed", strerror(errno));
32311 return HANDLER_ERROR;
32318 if (p->resp->ptr[0] != 'O' ||
32319 p->resp->ptr[1] != 'K') {
32320 - log_error_write(srv, __FILE__, __LINE__, "sbb",
32321 + log_error_write(srv, __FILE__, __LINE__, "sbb",
32322 "rrdtool-response:", p->cmd, p->resp);
32325 return HANDLER_ERROR;
32330 return HANDLER_GO_ON;
32333 -#define PATCH(x) \
32334 - p->conf.x = s->x;
32335 static int mod_rrd_patch_connection(server *srv, connection *con, plugin_data *p) {
32337 plugin_config *s = p->config_storage[0];
32339 - PATCH(path_rrdtool_bin);
32343 + PATCH_OPTION(path_rrdtool_bin);
32344 + PATCH_OPTION(path_rrd);
32346 p->conf.bytes_written_ptr = &(s->bytes_written);
32347 p->conf.bytes_read_ptr = &(s->bytes_read);
32348 p->conf.requests_ptr = &(s->requests);
32351 /* skip the first, the global context */
32352 for (i = 1; i < srv->config_context->used; i++) {
32353 data_config *dc = (data_config *)srv->config_context->data[i];
32354 s = p->config_storage[i];
32357 /* condition didn't match */
32358 if (!config_check_cond(srv, con, dc)) continue;
32362 for (j = 0; j < dc->value->used; j++) {
32363 data_unset *du = dc->value->data[j];
32366 if (buffer_is_equal_string(du->key, CONST_STR_LEN("rrdtool.db-name"))) {
32368 + PATCH_OPTION(path_rrd);
32369 /* get pointers to double values */
32372 p->conf.bytes_written_ptr = &(s->bytes_written);
32373 p->conf.bytes_read_ptr = &(s->bytes_read);
32374 p->conf.requests_ptr = &(s->requests);
32384 SETDEFAULTS_FUNC(mod_rrd_set_defaults) {
32385 plugin_data *p = p_d;
32388 - config_values_t cv[] = {
32390 + config_values_t cv[] = {
32391 { "rrdtool.binary", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
32392 { "rrdtool.db-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
32393 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
32397 if (!p) return HANDLER_ERROR;
32400 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
32403 for (i = 0; i < srv->config_context->used; i++) {
32407 s = calloc(1, sizeof(plugin_config));
32408 s->path_rrdtool_bin = buffer_init();
32409 s->path_rrd = buffer_init();
32411 s->bytes_written = 0;
32415 cv[0].destination = s->path_rrdtool_bin;
32416 cv[1].destination = s->path_rrd;
32419 p->config_storage[i] = s;
32422 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
32423 return HANDLER_ERROR;
32427 if (i > 0 && !buffer_is_empty(s->path_rrdtool_bin)) {
32428 /* path_rrdtool_bin is a global option */
32430 - log_error_write(srv, __FILE__, __LINE__, "s",
32432 + log_error_write(srv, __FILE__, __LINE__, "s",
32433 "rrdtool.binary can only be set as a global option.");
32436 return HANDLER_ERROR;
32443 p->conf.path_rrdtool_bin = p->config_storage[0]->path_rrdtool_bin;
32444 p->rrdtool_running = 0;
32447 /* check for dir */
32450 if (buffer_is_empty(p->conf.path_rrdtool_bin)) {
32451 - log_error_write(srv, __FILE__, __LINE__, "s",
32452 + log_error_write(srv, __FILE__, __LINE__, "s",
32453 "rrdtool.binary has to be set");
32454 return HANDLER_ERROR;
32458 /* open the pipe to rrdtool */
32459 if (mod_rrd_create_pipe(srv, p)) {
32460 return HANDLER_ERROR;
32464 p->rrdtool_running = 1;
32467 return HANDLER_GO_ON;
32470 TRIGGER_FUNC(mod_rrd_trigger) {
32471 plugin_data *p = p_d;
32475 if (!p->rrdtool_running) return HANDLER_GO_ON;
32476 if ((srv->cur_ts % 60) != 0) return HANDLER_GO_ON;
32479 for (i = 0; i < srv->config_context->used; i++) {
32480 plugin_config *s = p->config_storage[i];
32484 if (buffer_is_empty(s->path_rrd)) continue;
32487 /* write the data down every minute */
32490 if (HANDLER_GO_ON != mod_rrdtool_create_rrd(srv, p, s)) return HANDLER_ERROR;
32493 BUFFER_COPY_STRING_CONST(p->cmd, "update ");
32494 buffer_append_string_buffer(p->cmd, s->path_rrd);
32495 BUFFER_APPEND_STRING_CONST(p->cmd, " N:");
32496 @@ -381,69 +376,69 @@
32497 BUFFER_APPEND_STRING_CONST(p->cmd, ":");
32498 buffer_append_long(p->cmd, s->requests);
32499 BUFFER_APPEND_STRING_CONST(p->cmd, "\n");
32502 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
32503 p->rrdtool_running = 0;
32505 - log_error_write(srv, __FILE__, __LINE__, "ss",
32507 + log_error_write(srv, __FILE__, __LINE__, "ss",
32508 "rrdtool-write: failed", strerror(errno));
32511 return HANDLER_ERROR;
32515 buffer_prepare_copy(p->resp, 4096);
32516 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
32517 p->rrdtool_running = 0;
32519 - log_error_write(srv, __FILE__, __LINE__, "ss",
32521 + log_error_write(srv, __FILE__, __LINE__, "ss",
32522 "rrdtool-read: failed", strerror(errno));
32525 return HANDLER_ERROR;
32532 if (p->resp->ptr[0] != 'O' ||
32533 p->resp->ptr[1] != 'K') {
32534 p->rrdtool_running = 0;
32536 - log_error_write(srv, __FILE__, __LINE__, "sbb",
32538 + log_error_write(srv, __FILE__, __LINE__, "sbb",
32539 "rrdtool-response:", p->cmd, p->resp);
32542 return HANDLER_ERROR;
32545 s->bytes_written = 0;
32550 return HANDLER_GO_ON;
32553 REQUESTDONE_FUNC(mod_rrd_account) {
32554 plugin_data *p = p_d;
32557 mod_rrd_patch_connection(srv, con, p);
32560 *(p->conf.requests_ptr) += 1;
32561 *(p->conf.bytes_written_ptr) += con->bytes_written;
32562 *(p->conf.bytes_read_ptr) += con->bytes_read;
32565 return HANDLER_GO_ON;
32568 int mod_rrdtool_plugin_init(plugin *p) {
32569 p->version = LIGHTTPD_VERSION_ID;
32570 p->name = buffer_init_string("rrd");
32573 p->init = mod_rrd_init;
32574 p->cleanup = mod_rrd_free;
32575 p->set_defaults= mod_rrd_set_defaults;
32578 p->handle_trigger = mod_rrd_trigger;
32579 p->handle_request_done = mod_rrd_account;
32587 --- ../lighttpd-1.4.11/src/mod_scgi.c 2006-03-04 17:15:26.000000000 +0200
32588 +++ lighttpd-1.4.12/src/mod_scgi.c 2006-07-18 13:03:40.000000000 +0300
32590 #include <sys/types.h>
32591 -#include <unistd.h>
32594 #include <string.h>
32596 #include "connections.h"
32597 #include "response.h"
32598 #include "joblist.h"
32599 +#include "http_resp.h"
32601 #include "plugin.h"
32606 #include "sys-socket.h"
32608 +#include "sys-files.h"
32609 +#include "sys-strings.h"
32610 +#include "sys-process.h"
32612 #ifndef UNIX_PATH_MAX
32613 # define UNIX_PATH_MAX 108
32614 @@ -46,30 +48,29 @@
32615 enum {EOL_UNSET, EOL_N, EOL_RN};
32623 * - add timeout for a connect to a non-scgi process
32624 * (use state_timestamp + state)
32629 typedef struct scgi_proc {
32630 size_t id; /* id will be between 1 and max_procs */
32631 buffer *socket; /* config.socket + "-" + id */
32632 unsigned port; /* config.port + pno */
32634 - pid_t pid; /* PID of the spawned process (0 if not spawned locally) */
32636 + pid_t pid; /* PID of the spawned process (0 if not spawned locally) */
32638 size_t load; /* number of requests waiting on this process */
32640 time_t last_used; /* see idle_timeout */
32641 size_t requests; /* see max_requests */
32642 struct scgi_proc *prev, *next; /* see first */
32645 time_t disable_ts; /* replace by host->something */
32650 enum { PROC_STATE_UNSET, /* init-phase */
32652 PROC_STATE_KILLED, /* was killed as we don't have the load anymore */
32653 PROC_STATE_DIED, /* marked as dead, should be restarted */
32654 PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
32660 @@ -86,20 +87,20 @@
32661 * sorted by lowest load
32663 * whenever a job is done move it up in the list
32664 - * until it is sorted, move it down as soon as the
32665 + * until it is sorted, move it down as soon as the
32668 - scgi_proc *first;
32669 - scgi_proc *unused_procs;
32670 + scgi_proc *first;
32671 + scgi_proc *unused_procs;
32675 * spawn at least min_procs, at max_procs.
32677 - * as soon as the load of the first entry
32678 + * as soon as the load of the first entry
32679 * is max_load_per_proc we spawn a new one
32680 - * and add it to the first entry and give it
32681 + * and add it to the first entry and give it
32687 unsigned short min_procs;
32688 @@ -111,44 +112,44 @@
32691 * kick the process from the list if it was not
32692 - * used for idle_timeout until min_procs is
32693 + * used for idle_timeout until min_procs is
32694 * reached. this helps to get the processlist
32695 * small again we had a small peak load.
32700 unsigned short idle_timeout;
32704 * time after a disabled remote connection is tried to be re-enabled
32712 unsigned short disable_time;
32715 * same scgi processes get a little bit larger
32716 - * than wanted. max_requests_per_proc kills a
32717 + * than wanted. max_requests_per_proc kills a
32718 * process after a number of handled requests.
32721 size_t max_requests_per_proc;
32732 - * if host is one of the local IP adresses the
32733 + * if host is one of the local IP adresses the
32734 * whole connection is local
32736 * if tcp/ip should be used host AND port have
32737 - * to be specified
32741 + * to be specified
32745 unsigned short port;
32748 @@ -161,7 +162,7 @@
32750 buffer *unixsocket;
32752 - /* if socket is local we can start the scgi
32753 + /* if socket is local we can start the scgi
32756 * bin-path is the path to the binary
32757 @@ -169,19 +170,19 @@
32758 * check min_procs and max_procs for the number
32759 * of process to start-up
32761 - buffer *bin_path;
32763 - /* bin-path is set bin-environment is taken to
32764 + buffer *bin_path;
32766 + /* bin-path is set bin-environment is taken to
32767 * create the environement before starting the
32775 array *bin_env_copy;
32779 - * docroot-translation between URL->phys and the
32780 + * docroot-translation between URL->phys and the
32784 @@ -192,7 +193,7 @@
32788 - * check_local tell you if the phys file is stat()ed
32789 + * check_local tell you if the phys file is stat()ed
32790 * or not. FastCGI doesn't care if the service is
32791 * remote. If the web-server side doesn't contain
32792 * the scgi-files we should not stat() for them
32793 @@ -202,33 +203,33 @@
32796 * append PATH_INFO to SCRIPT_FILENAME
32799 * php needs this if cgi.fix_pathinfo is provied
32805 ssize_t load; /* replace by host->load */
32807 size_t max_id; /* corresponds most of the time to
32811 only if a process is killed max_id waits for the process itself
32812 to die and decrements its afterwards */
32813 } scgi_extension_host;
32816 * one extension can have multiple hosts assigned
32817 - * one host can spawn additional processes on the same
32818 + * one host can spawn additional processes on the same
32819 * socket (if we control it)
32821 * ext -> host -> procs
32824 - * if the scgi process is remote that whole goes down
32825 + * if the scgi process is remote that whole goes down
32828 * ext -> host -> procs
32832 * in case of PHP and FCGI_CHILDREN we have again a procs
32833 * but we don't control it directly.
32834 @@ -239,7 +240,7 @@
32835 buffer *key; /* like .php */
32837 scgi_extension_host **hosts;
32843 @@ -253,14 +254,14 @@
32861 @@ -268,52 +269,51 @@
32862 /* generic plugin data, shared between all connections */
32871 - buffer *parse_response;
32876 plugin_config **config_storage;
32879 plugin_config conf; /* this is only used as long as no handler_ctx is setup */
32882 /* connection specific data */
32883 -typedef enum { FCGI_STATE_INIT, FCGI_STATE_CONNECT, FCGI_STATE_PREPARE_WRITE,
32884 - FCGI_STATE_WRITE, FCGI_STATE_READ
32887 + SCGI_STATE_CONNECT,
32888 + SCGI_STATE_PREPARE_WRITE,
32889 + SCGI_STATE_WRITE,
32890 + SCGI_STATE_RESPONSE_HEADER,
32891 + SCGI_STATE_RESPONSE_CONTENT,
32893 } scgi_connection_state_t;
32896 - buffer *response;
32897 - size_t response_len;
32898 - int response_type;
32899 - int response_padding;
32902 scgi_extension_host *host;
32905 scgi_connection_state_t state;
32906 time_t state_timestamp;
32909 int reconnects; /* number of reconnect attempts */
32916 - buffer *response_header;
32919 int delayed; /* flag to mark that the connect() is delayed */
32923 - int fd; /* fd to the scgi process */
32924 - int fde_ndx; /* index into the fd-event buffer */
32925 + iosocket *sock; /* fd to the scgi process */
32931 plugin_config conf;
32934 connection *remote_conn; /* dumb pointer */
32935 plugin_data *plugin_data; /* dumb pointer */
32937 @@ -328,42 +328,30 @@
32939 static handler_ctx * handler_ctx_init() {
32940 handler_ctx * hctx;
32943 hctx = calloc(1, sizeof(*hctx));
32946 - hctx->fde_ndx = -1;
32948 - hctx->response = buffer_init();
32949 - hctx->response_header = buffer_init();
32952 + hctx->sock = iosocket_init();;
32954 hctx->request_id = 0;
32955 - hctx->state = FCGI_STATE_INIT;
32956 + hctx->state = SCGI_STATE_INIT;
32959 - hctx->response_len = 0;
32960 - hctx->response_type = 0;
32961 - hctx->response_padding = 0;
32965 hctx->reconnects = 0;
32967 hctx->wb = chunkqueue_init();
32969 + hctx->rb = chunkqueue_init();
32974 static void handler_ctx_free(handler_ctx *hctx) {
32975 - buffer_free(hctx->response);
32976 - buffer_free(hctx->response_header);
32978 chunkqueue_free(hctx->wb);
32981 - if (hctx->rb->ptr) free(hctx->rb->ptr);
32985 + chunkqueue_free(hctx->rb);
32987 + iosocket_free(hctx->sock);
32992 @@ -372,20 +360,20 @@
32994 f = calloc(1, sizeof(*f));
32995 f->socket = buffer_init();
33005 void scgi_process_free(scgi_proc *f) {
33009 scgi_process_free(f->next);
33012 buffer_free(f->socket);
33018 @@ -400,62 +388,62 @@
33019 f->bin_path = buffer_init();
33020 f->bin_env = array_init();
33021 f->bin_env_copy = array_init();
33027 void scgi_host_free(scgi_extension_host *h) {
33031 buffer_free(h->host);
33032 buffer_free(h->unixsocket);
33033 buffer_free(h->docroot);
33034 buffer_free(h->bin_path);
33035 array_free(h->bin_env);
33036 array_free(h->bin_env_copy);
33039 scgi_process_free(h->first);
33040 scgi_process_free(h->unused_procs);
33048 scgi_exts *scgi_extensions_init() {
33051 f = calloc(1, sizeof(*f));
33057 void scgi_extensions_free(scgi_exts *f) {
33064 for (i = 0; i < f->used; i++) {
33065 scgi_extension *fe;
33072 for (j = 0; j < fe->used; j++) {
33073 scgi_extension_host *h;
33083 buffer_free(fe->key);
33097 @@ -504,99 +492,103 @@
33101 - fe->hosts[fe->used++] = fh;
33102 + fe->hosts[fe->used++] = fh;
33109 INIT_FUNC(mod_scgi_init) {
33113 p = calloc(1, sizeof(*p));
33116 p->scgi_env = buffer_init();
33119 p->path = buffer_init();
33120 - p->parse_response = buffer_init();
33122 + p->resp = http_response_init();
33128 FREE_FUNC(mod_scgi_free) {
33129 plugin_data *p = p_d;
33134 buffer_free(p->scgi_env);
33135 buffer_free(p->path);
33136 - buffer_free(p->parse_response);
33138 + http_response_free(p->resp);
33140 if (p->config_storage) {
33142 for (i = 0; i < srv->config_context->used; i++) {
33143 plugin_config *s = p->config_storage[i];
33152 for (j = 0; j < exts->used; j++) {
33153 scgi_extension *ex;
33156 ex = exts->exts[j];
33159 for (n = 0; n < ex->used; n++) {
33161 scgi_extension_host *host;
33164 host = ex->hosts[n];
33167 for (proc = host->first; proc; proc = proc->next) {
33169 if (proc->pid != 0) kill(proc->pid, SIGTERM);
33171 - if (proc->is_local &&
33174 + if (proc->is_local &&
33175 !buffer_is_empty(proc->socket)) {
33176 unlink(proc->socket->ptr);
33181 for (proc = host->unused_procs; proc; proc = proc->next) {
33183 if (proc->pid != 0) kill(proc->pid, SIGTERM);
33185 - if (proc->is_local &&
33188 + if (proc->is_local &&
33189 !buffer_is_empty(proc->socket)) {
33190 unlink(proc->socket->ptr);
33197 scgi_extensions_free(s->exts);
33202 free(p->config_storage);
33209 return HANDLER_GO_ON;
33212 static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
33216 if (!key || !val) return -1;
33219 dst = malloc(key_len + val_len + 3);
33220 memcpy(dst, key, key_len);
33221 dst[key_len] = '=';
33222 /* add the \0 from the value */
33223 memcpy(dst + key_len + 1, val, val_len + 1);
33226 if (env->size == 0) {
33228 env->ptr = malloc(env->size * sizeof(*env->ptr));
33229 @@ -604,13 +596,13 @@
33231 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
33235 env->ptr[env->used++] = dst;
33241 -static int scgi_spawn_connection(server *srv,
33242 +static int scgi_spawn_connection(server *srv,
33244 scgi_extension_host *host,
33246 @@ -622,31 +614,27 @@
33248 struct sockaddr_in scgi_addr_in;
33249 struct sockaddr *scgi_addr;
33260 if (p->conf.debug) {
33261 log_error_write(srv, __FILE__, __LINE__, "sdb",
33262 "new proc, socket:", proc->port, proc->socket);
33266 if (!buffer_is_empty(proc->socket)) {
33267 memset(&scgi_addr, 0, sizeof(scgi_addr));
33270 #ifdef HAVE_SYS_UN_H
33271 scgi_addr_un.sun_family = AF_UNIX;
33272 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
33276 servlen = SUN_LEN(&scgi_addr_un);
33278 - /* stevens says: */
33279 - servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
33282 socket_type = AF_UNIX;
33283 scgi_addr = (struct sockaddr *) &scgi_addr_un;
33285 @@ -656,115 +644,115 @@
33288 scgi_addr_in.sin_family = AF_INET;
33291 if (buffer_is_empty(host->host)) {
33292 scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
33294 struct hostent *he;
33297 /* set a usefull default */
33298 scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
33303 if (NULL == (he = gethostbyname(host->host->ptr))) {
33304 - log_error_write(srv, __FILE__, __LINE__,
33305 - "sdb", "gethostbyname failed: ",
33306 + log_error_write(srv, __FILE__, __LINE__,
33307 + "sdb", "gethostbyname failed: ",
33308 h_errno, host->host);
33313 if (he->h_addrtype != AF_INET) {
33314 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
33319 if (he->h_length != sizeof(struct in_addr)) {
33320 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
33325 memcpy(&(scgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
33329 scgi_addr_in.sin_port = htons(proc->port);
33330 servlen = sizeof(scgi_addr_in);
33333 socket_type = AF_INET;
33334 scgi_addr = (struct sockaddr *) &scgi_addr_in;
33338 if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
33339 - log_error_write(srv, __FILE__, __LINE__, "ss",
33340 + log_error_write(srv, __FILE__, __LINE__, "ss",
33341 "failed:", strerror(errno));
33346 if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
33347 /* server is not up, spawn in */
33352 if (!buffer_is_empty(proc->socket)) {
33353 unlink(proc->socket->ptr);
33360 /* reopen socket */
33361 if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
33362 - log_error_write(srv, __FILE__, __LINE__, "ss",
33363 + log_error_write(srv, __FILE__, __LINE__, "ss",
33364 "socket failed:", strerror(errno));
33370 if (setsockopt(scgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
33371 - log_error_write(srv, __FILE__, __LINE__, "ss",
33372 + log_error_write(srv, __FILE__, __LINE__, "ss",
33373 "socketsockopt failed:", strerror(errno));
33378 /* create socket */
33379 if (-1 == bind(scgi_fd, scgi_addr, servlen)) {
33380 - log_error_write(srv, __FILE__, __LINE__, "sbds",
33381 - "bind failed for:",
33384 + log_error_write(srv, __FILE__, __LINE__, "sbds",
33385 + "bind failed for:",
33393 if (-1 == listen(scgi_fd, 1024)) {
33394 - log_error_write(srv, __FILE__, __LINE__, "ss",
33395 + log_error_write(srv, __FILE__, __LINE__, "ss",
33396 "listen failed:", strerror(errno));
33403 switch ((child = fork())) {
33413 /* create environment */
33419 /* we don't need the client socket */
33420 for (fd = 3; fd < 256; fd++) {
33421 if (fd != 2 && fd != scgi_fd) close(fd);
33425 /* build clean environment */
33426 if (host->bin_env_copy->used) {
33427 for (i = 0; i < host->bin_env_copy->used; i++) {
33428 data_string *ds = (data_string *)host->bin_env_copy->data[i];
33432 if (NULL != (ge = getenv(ds->value->ptr))) {
33433 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
33435 @@ -772,44 +760,44 @@
33437 for (i = 0; environ[i]; i++) {
33441 if (NULL != (eq = strchr(environ[i], '='))) {
33442 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
33448 /* create environment */
33449 for (i = 0; i < host->bin_env->used; i++) {
33450 data_string *ds = (data_string *)host->bin_env->data[i];
33453 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
33457 for (i = 0; i < env.used; i++) {
33458 /* search for PHP_FCGI_CHILDREN */
33459 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
33463 /* not found, add a default */
33464 if (i == env.used) {
33465 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
33469 env.ptr[env.used] = NULL;
33473 buffer_copy_string(b, "exec ");
33474 buffer_append_string_buffer(b, host->bin_path);
33478 execle("/bin/sh", "sh", "-c", b->ptr, NULL, env.ptr);
33480 - log_error_write(srv, __FILE__, __LINE__, "sbs",
33482 + log_error_write(srv, __FILE__, __LINE__, "sbs",
33483 "execl failed for:", host->bin_path, strerror(errno));
33492 @@ -817,32 +805,32 @@
33499 select(0, NULL, NULL, NULL, &tv);
33502 switch (waitpid(child, &status, WNOHANG)) {
33504 /* child still running after timeout, good */
33507 /* no PID found ? should never happen */
33508 - log_error_write(srv, __FILE__, __LINE__, "ss",
33509 + log_error_write(srv, __FILE__, __LINE__, "ss",
33510 "pid not found:", strerror(errno));
33513 /* the child should not terminate at all */
33514 if (WIFEXITED(status)) {
33515 - log_error_write(srv, __FILE__, __LINE__, "sd",
33516 - "child exited (is this a SCGI binary ?):",
33517 + log_error_write(srv, __FILE__, __LINE__, "sd",
33518 + "child exited (is this a SCGI binary ?):",
33519 WEXITSTATUS(status));
33520 } else if (WIFSIGNALED(status)) {
33521 - log_error_write(srv, __FILE__, __LINE__, "sd",
33522 - "child signaled:",
33523 + log_error_write(srv, __FILE__, __LINE__, "sd",
33524 + "child signaled:",
33527 - log_error_write(srv, __FILE__, __LINE__, "sd",
33528 - "child died somehow:",
33529 + log_error_write(srv, __FILE__, __LINE__, "sd",
33530 + "child died somehow:",
33534 @@ -852,26 +840,26 @@
33536 proc->last_used = srv->cur_ts;
33537 proc->is_local = 1;
33544 proc->is_local = 0;
33548 if (p->conf.debug) {
33549 log_error_write(srv, __FILE__, __LINE__, "sb",
33550 "(debug) socket is already used, won't spawn:",
33556 proc->state = PROC_STATE_RUNNING;
33557 host->active_procs++;
33566 @@ -880,89 +868,89 @@
33567 plugin_data *p = p_d;
33571 - config_values_t cv[] = {
33573 + config_values_t cv[] = {
33574 { "scgi.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
33575 { "scgi.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
33576 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
33580 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
33583 for (i = 0; i < srv->config_context->used; i++) {
33588 s = malloc(sizeof(plugin_config));
33589 s->exts = scgi_extensions_init();
33593 cv[0].destination = s->exts;
33594 cv[1].destination = &(s->debug);
33597 p->config_storage[i] = s;
33598 ca = ((data_config *)srv->config_context->data[i])->value;
33601 if (0 != config_insert_values_global(srv, ca, cv)) {
33602 return HANDLER_ERROR;
33612 if (NULL != (du = array_get_element(ca, "scgi.server"))) {
33614 data_array *da = (data_array *)du;
33617 if (du->type != TYPE_ARRAY) {
33618 - log_error_write(srv, __FILE__, __LINE__, "sss",
33619 + log_error_write(srv, __FILE__, __LINE__, "sss",
33620 "unexpected type for key: ", "scgi.server", "array of strings");
33623 return HANDLER_ERROR;
33628 - * scgi.server = ( "<ext>" => ( ... ),
33632 + * scgi.server = ( "<ext>" => ( ... ),
33633 * "<ext>" => ( ... ) )
33637 for (j = 0; j < da->value->used; j++) {
33639 data_array *da_ext = (data_array *)da->value->data[j];
33642 if (da->value->data[j]->type != TYPE_ARRAY) {
33643 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
33644 - "unexpected type for key: ", "scgi.server",
33645 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
33646 + "unexpected type for key: ", "scgi.server",
33647 "[", da->value->data[j]->key, "](string)");
33650 return HANDLER_ERROR;
33654 - * da_ext->key == name of the extension
33657 + * da_ext->key == name of the extension
33661 - * scgi.server = ( "<ext>" =>
33662 - * ( "<host>" => ( ... ),
33665 + * scgi.server = ( "<ext>" =>
33666 + * ( "<host>" => ( ... ),
33667 * "<host>" => ( ... )
33674 for (n = 0; n < da_ext->value->used; n++) {
33675 data_array *da_host = (data_array *)da_ext->value->data[n];
33678 scgi_extension_host *df;
33680 - config_values_t fcv[] = {
33682 + config_values_t fcv[] = {
33683 { "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
33684 { "docroot", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
33685 { "socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
33686 { "bin-path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
33689 { "check-local", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
33690 { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
33691 { "min-procs-not-working", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 this is broken for now */
33692 @@ -970,37 +958,37 @@
33693 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
33694 { "idle-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
33695 { "disable-time", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
33698 { "bin-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
33699 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
33704 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
33708 if (da_host->type != TYPE_ARRAY) {
33709 - log_error_write(srv, __FILE__, __LINE__, "ssSBS",
33710 - "unexpected type for key:",
33712 + log_error_write(srv, __FILE__, __LINE__, "ssSBS",
33713 + "unexpected type for key:",
33715 "[", da_host->key, "](string)");
33718 return HANDLER_ERROR;
33722 df = scgi_host_init();
33725 df->check_local = 1;
33728 df->max_load_per_proc = 1;
33729 df->idle_timeout = 60;
33730 df->disable_time = 60;
33733 fcv[0].destination = df->host;
33734 fcv[1].destination = df->docroot;
33735 fcv[2].destination = df->unixsocket;
33736 fcv[3].destination = df->bin_path;
33739 fcv[4].destination = &(df->check_local);
33740 fcv[5].destination = &(df->port);
33741 fcv[6].destination = &(df->min_procs);
33742 @@ -1008,47 +996,47 @@
33743 fcv[8].destination = &(df->max_load_per_proc);
33744 fcv[9].destination = &(df->idle_timeout);
33745 fcv[10].destination = &(df->disable_time);
33748 fcv[11].destination = df->bin_env;
33749 fcv[12].destination = df->bin_env_copy;
33754 if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
33755 return HANDLER_ERROR;
33758 - if ((!buffer_is_empty(df->host) || df->port) &&
33760 + if ((!buffer_is_empty(df->host) || df->port) &&
33761 !buffer_is_empty(df->unixsocket)) {
33762 - log_error_write(srv, __FILE__, __LINE__, "s",
33763 + log_error_write(srv, __FILE__, __LINE__, "s",
33764 "either host+port or socket");
33767 return HANDLER_ERROR;
33771 if (!buffer_is_empty(df->unixsocket)) {
33772 /* unix domain socket */
33775 if (df->unixsocket->used > UNIX_PATH_MAX - 2) {
33776 - log_error_write(srv, __FILE__, __LINE__, "s",
33777 + log_error_write(srv, __FILE__, __LINE__, "s",
33778 "path of the unixdomain socket is too large");
33779 return HANDLER_ERROR;
33784 - if (buffer_is_empty(df->host) &&
33786 + if (buffer_is_empty(df->host) &&
33787 buffer_is_empty(df->bin_path)) {
33788 - log_error_write(srv, __FILE__, __LINE__, "sbbbs",
33789 - "missing key (string):",
33790 + log_error_write(srv, __FILE__, __LINE__, "sbbbs",
33791 + "missing key (string):",
33798 return HANDLER_ERROR;
33799 } else if (df->port == 0) {
33800 - log_error_write(srv, __FILE__, __LINE__, "sbbbs",
33801 - "missing key (short):",
33802 + log_error_write(srv, __FILE__, __LINE__, "sbbbs",
33803 + "missing key (short):",
33807 @@ -1056,14 +1044,14 @@
33808 return HANDLER_ERROR;
33812 - if (!buffer_is_empty(df->bin_path)) {
33814 + if (!buffer_is_empty(df->bin_path)) {
33815 /* a local socket + self spawning */
33819 if (df->min_procs > df->max_procs) df->max_procs = df->min_procs;
33820 if (df->max_load_per_proc < 1) df->max_load_per_proc = 0;
33824 log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
33825 "--- scgi spawning local",
33826 @@ -1073,7 +1061,7 @@
33827 "\n\tmin-procs:", df->min_procs,
33828 "\n\tmax-procs:", df->max_procs);
33832 for (pno = 0; pno < df->min_procs; pno++) {
33835 @@ -1088,7 +1076,7 @@
33836 buffer_append_string(proc->socket, "-");
33837 buffer_append_long(proc->socket, pno);
33842 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
33843 "--- scgi spawning",
33844 @@ -1096,53 +1084,53 @@
33845 "\n\tsocket", df->unixsocket,
33846 "\n\tcurrent:", pno, "/", df->min_procs);
33850 if (scgi_spawn_connection(srv, p, df, proc)) {
33851 log_error_write(srv, __FILE__, __LINE__, "s",
33852 "[ERROR]: spawning fcgi failed.");
33853 return HANDLER_ERROR;
33857 proc->next = df->first;
33858 if (df->first) df->first->prev = proc;
33867 fp = scgi_process_init();
33868 fp->id = df->num_procs++;
33870 df->active_procs++;
33871 fp->state = PROC_STATE_RUNNING;
33874 if (buffer_is_empty(df->unixsocket)) {
33875 fp->port = df->port;
33877 buffer_copy_string_buffer(fp->socket, df->unixsocket);
33889 /* if extension already exists, take it */
33890 scgi_extension_insert(s->exts, da_ext->key, df);
33897 return HANDLER_GO_ON;
33900 static int scgi_set_state(server *srv, handler_ctx *hctx, scgi_connection_state_t state) {
33901 hctx->state = state;
33902 hctx->state_timestamp = srv->cur_ts;
33908 @@ -1150,35 +1138,35 @@
33909 void scgi_connection_cleanup(server *srv, handler_ctx *hctx) {
33914 if (NULL == hctx) return;
33917 p = hctx->plugin_data;
33918 con = hctx->remote_conn;
33921 if (con->mode != p->id) {
33926 - if (hctx->fd != -1) {
33927 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
33928 - fdevent_unregister(srv->ev, hctx->fd);
33931 + if (hctx->sock->fd != -1) {
33932 + fdevent_event_del(srv->ev, hctx->sock);
33933 + fdevent_unregister(srv->ev, hctx->sock);
33934 + closesocket(hctx->sock->fd);
33935 + hctx->sock->fd = -1;
33940 if (hctx->host && hctx->proc) {
33941 hctx->host->load--;
33944 if (hctx->got_proc) {
33945 /* after the connect the process gets a load */
33946 hctx->proc->load--;
33949 if (p->conf.debug) {
33950 log_error_write(srv, __FILE__, __LINE__, "sddb",
33955 hctx->proc->pid, hctx->proc->socket);
33958 @@ -1186,87 +1174,87 @@
33959 scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
33964 handler_ctx_free(hctx);
33965 - con->plugin_ctx[p->id] = NULL;
33966 + con->plugin_ctx[p->id] = NULL;
33969 static int scgi_reconnect(server *srv, handler_ctx *hctx) {
33970 plugin_data *p = hctx->plugin_data;
33981 * connect was ok, connection was accepted
33982 * but the php accept loop checks after the accept if it should die or not.
33984 - * if yes we can only detect it at a write()
33987 + * if yes we can only detect it at a write()
33989 * next step is resetting this attemp and setup a connection again
33992 * if we have more then 5 reconnects for the same request, die
33999 * we have a connection but the child died by some other reason
34004 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
34005 - fdevent_unregister(srv->ev, hctx->fd);
34008 + fdevent_event_del(srv->ev, hctx->sock);
34009 + fdevent_unregister(srv->ev, hctx->sock);
34010 + closesocket(hctx->sock->fd);
34013 - scgi_set_state(srv, hctx, FCGI_STATE_INIT);
34016 + scgi_set_state(srv, hctx, SCGI_STATE_INIT);
34018 hctx->request_id = 0;
34019 hctx->reconnects++;
34022 if (p->conf.debug) {
34023 log_error_write(srv, __FILE__, __LINE__, "sddb",
34028 hctx->proc->pid, hctx->proc->socket);
34032 hctx->proc->load--;
34033 scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
34040 static handler_t scgi_connection_reset(server *srv, connection *con, void *p_d) {
34041 plugin_data *p = p_d;
34044 scgi_connection_cleanup(srv, con->plugin_ctx[p->id]);
34047 return HANDLER_GO_ON;
34051 static int scgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
34055 if (!key || !val) return -1;
34058 len = key_len + val_len + 2;
34061 buffer_prepare_append(env, len);
34063 - /* include the NUL */
34064 + /* include the NUL */
34065 memcpy(env->ptr + env->used, key, key_len + 1);
34066 env->used += key_len + 1;
34067 memcpy(env->ptr + env->used, val, val_len + 1);
34068 env->used += val_len + 1;
34081 @@ -1280,24 +1268,21 @@
34082 struct sockaddr_un scgi_addr_un;
34087 scgi_extension_host *host = hctx->host;
34088 scgi_proc *proc = hctx->proc;
34089 - int scgi_fd = hctx->fd;
34091 + int scgi_fd = hctx->sock->fd;
34093 memset(&scgi_addr, 0, sizeof(scgi_addr));
34096 if (!buffer_is_empty(proc->socket)) {
34097 #ifdef HAVE_SYS_UN_H
34098 /* use the unix domain socket */
34099 scgi_addr_un.sun_family = AF_UNIX;
34100 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
34103 servlen = SUN_LEN(&scgi_addr_un);
34105 - /* stevens says: */
34106 - servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
34109 scgi_addr = (struct sockaddr *) &scgi_addr_un;
34112 @@ -1305,105 +1290,105 @@
34114 scgi_addr_in.sin_family = AF_INET;
34115 if (0 == inet_aton(host->host->ptr, &(scgi_addr_in.sin_addr))) {
34116 - log_error_write(srv, __FILE__, __LINE__, "sbs",
34117 - "converting IP-adress failed for", host->host,
34118 + log_error_write(srv, __FILE__, __LINE__, "sbs",
34119 + "converting IP-adress failed for", host->host,
34120 "\nBe sure to specify an IP address here");
34125 scgi_addr_in.sin_port = htons(proc->port);
34126 servlen = sizeof(scgi_addr_in);
34129 scgi_addr = (struct sockaddr *) &scgi_addr_in;
34133 if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
34134 - if (errno == EINPROGRESS ||
34135 + if (errno == EINPROGRESS ||
34136 errno == EALREADY ||
34138 if (hctx->conf.debug) {
34139 - log_error_write(srv, __FILE__, __LINE__, "sd",
34140 + log_error_write(srv, __FILE__, __LINE__, "sd",
34141 "connect delayed, will continue later:", scgi_fd);
34147 - log_error_write(srv, __FILE__, __LINE__, "sdsddb",
34148 - "connect failed:", scgi_fd,
34149 + log_error_write(srv, __FILE__, __LINE__, "sdsddb",
34150 + "connect failed:", scgi_fd,
34151 strerror(errno), errno,
34152 proc->port, proc->socket);
34154 if (errno == EAGAIN) {
34155 /* this is Linux only */
34157 - log_error_write(srv, __FILE__, __LINE__, "s",
34159 + log_error_write(srv, __FILE__, __LINE__, "s",
34160 "If this happend on Linux: You have been run out of local ports. "
34161 "Check the manual, section Performance how to handle this.");
34169 if (hctx->conf.debug > 1) {
34170 - log_error_write(srv, __FILE__, __LINE__, "sd",
34171 + log_error_write(srv, __FILE__, __LINE__, "sd",
34172 "connect succeeded: ", scgi_fd);
34181 static int scgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
34185 for (i = 0; i < con->request.headers->used; i++) {
34189 ds = (data_string *)con->request.headers->data[i];
34192 if (ds->value->used && ds->key->used) {
34194 buffer_reset(srv->tmp_buf);
34197 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
34198 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
34199 srv->tmp_buf->used--;
34203 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
34204 for (j = 0; j < ds->key->used - 1; j++) {
34205 - srv->tmp_buf->ptr[srv->tmp_buf->used++] =
34206 - light_isalpha(ds->key->ptr[j]) ?
34207 + srv->tmp_buf->ptr[srv->tmp_buf->used++] =
34208 + light_isalpha(ds->key->ptr[j]) ?
34209 ds->key->ptr[j] & ~32 : '_';
34211 srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
34214 scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
34219 for (i = 0; i < con->environment->used; i++) {
34223 ds = (data_string *)con->environment->data[i];
34226 if (ds->value->used && ds->key->used) {
34228 buffer_reset(srv->tmp_buf);
34231 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
34232 for (j = 0; j < ds->key->used - 1; j++) {
34233 - srv->tmp_buf->ptr[srv->tmp_buf->used++] =
34234 - isalpha((unsigned char)ds->key->ptr[j]) ?
34235 + srv->tmp_buf->ptr[srv->tmp_buf->used++] =
34236 + isalpha((unsigned char)ds->key->ptr[j]) ?
34237 toupper((unsigned char)ds->key->ptr[j]) : '_';
34239 srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
34242 scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
34250 @@ -1415,20 +1400,20 @@
34251 char b2[INET6_ADDRSTRLEN + 1];
34256 plugin_data *p = hctx->plugin_data;
34257 scgi_extension_host *host= hctx->host;
34259 connection *con = hctx->remote_conn;
34260 server_socket *srv_sock = con->srv_socket;
34263 sock_addr our_addr;
34264 socklen_t our_addr_len;
34267 buffer_prepare_copy(p->scgi_env, 1024);
34269 /* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
34272 /* request.content_length < SSIZE_MAX, see request.c */
34273 ltostr(buf, con->request.content_length);
34274 scgi_env_add(p->scgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
34275 @@ -1436,13 +1421,13 @@
34278 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
34281 if (con->server_name->used) {
34282 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
34285 - s = inet_ntop(srv_sock->addr.plain.sa_family,
34286 - srv_sock->addr.plain.sa_family == AF_INET6 ?
34287 + s = inet_ntop(srv_sock->addr.plain.sa_family,
34288 + srv_sock->addr.plain.sa_family == AF_INET6 ?
34289 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
34290 (const void *) &(srv_sock->addr.ipv4.sin_addr),
34292 @@ -1451,47 +1436,47 @@
34294 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
34298 scgi_env_add(p->scgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
34304 ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
34306 ntohs(srv_sock->addr.ipv4.sin_port)
34311 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
34314 /* get the server-side of the connection to the client */
34315 our_addr_len = sizeof(our_addr);
34317 - if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
34319 + if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
34320 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
34322 s = inet_ntop_cache_get_ip(srv, &(our_addr));
34324 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
34330 ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
34332 ntohs(con->dst_addr.ipv4.sin_port)
34337 scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
34340 s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
34341 scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
34344 if (!buffer_is_empty(con->authed_user)) {
34345 scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_USER"),
34346 CONST_BUF_LEN(con->authed_user));
34352 * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
34353 @@ -1500,12 +1485,12 @@
34356 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
34359 if (!buffer_is_empty(con->request.pathinfo)) {
34360 scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
34363 /* PATH_TRANSLATED is only defined if PATH_INFO is set */
34366 if (!buffer_is_empty(host->docroot)) {
34367 buffer_copy_string_buffer(p->path, host->docroot);
34369 @@ -1526,19 +1511,19 @@
34372 if (!buffer_is_empty(host->docroot)) {
34374 - * rewrite SCRIPT_FILENAME
34377 + * rewrite SCRIPT_FILENAME
34382 buffer_copy_string_buffer(p->path, host->docroot);
34383 buffer_append_string_buffer(p->path, con->uri.path);
34386 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
34387 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
34389 buffer_copy_string_buffer(p->path, con->physical.path);
34392 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
34393 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
34395 @@ -1551,30 +1536,30 @@
34397 scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
34401 s = get_http_method_name(con->request.http_method);
34402 scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
34403 scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
34404 s = get_http_version_name(con->request.http_version);
34405 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
34409 if (srv_sock->is_ssl) {
34410 scgi_env_add(p->scgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
34415 scgi_env_add_request_headers(srv, con, p);
34417 b = chunkqueue_get_append_buffer(hctx->wb);
34420 buffer_append_long(b, p->scgi_env->used);
34421 buffer_append_string_len(b, CONST_STR_LEN(":"));
34422 buffer_append_string_len(b, (const char *)p->scgi_env->ptr, p->scgi_env->used);
34423 buffer_append_string_len(b, CONST_STR_LEN(","));
34425 hctx->wb->bytes_in += b->used - 1;
34428 if (con->request.content_length) {
34429 chunkqueue *req_cq = con->request_content_queue;
34431 @@ -1587,7 +1572,7 @@
34433 /* we announce toWrite octects
34434 * now take all the request_content chunk that we need to fill this request
34438 switch (req_c->type) {
34440 @@ -1615,293 +1600,170 @@
34442 req_c->offset += weHave;
34443 req_cq->bytes_out += weHave;
34446 hctx->wb->bytes_in += weHave;
34460 for (i = 0; i < hctx->write_buffer->used; i++) {
34461 fprintf(stderr, "%02x ", hctx->write_buffer->ptr[i]);
34462 if ((i+1) % 16 == 0) {
34464 for (j = i-15; j <= i; j++) {
34465 - fprintf(stderr, "%c",
34466 + fprintf(stderr, "%c",
34467 isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
34469 fprintf(stderr, "\n");
34477 -static int scgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
34484 - buffer_copy_string_buffer(p->parse_response, in);
34486 - for (s = p->parse_response->ptr;
34487 - NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n')));
34488 - s = ns + (eol == EOL_RN ? 2 : 1), line++) {
34489 - const char *key, *value;
34496 - 0 == strncmp(s, "HTTP/1.", 7)) {
34497 - /* non-parsed header ... we parse them anyway */
34499 - if ((s[7] == '1' ||
34503 - /* after the space should be a status code for us */
34505 - status = strtol(s+9, NULL, 10);
34507 - if (con->http_status >= 100 &&
34508 - con->http_status < 1000) {
34509 - /* we expected 3 digits and didn't got them */
34510 - con->parsed_response |= HTTP_STATUS;
34511 - con->http_status = status;
34517 - if (NULL == (value = strchr(s, ':'))) {
34518 - /* we expect: "<key>: <value>\r\n" */
34522 - key_len = value - key;
34526 - while (*value == ' ' || *value == '\t') value++;
34528 - if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
34529 - ds = data_response_init();
34531 - buffer_copy_string_len(ds->key, key, key_len);
34532 - buffer_copy_string(ds->value, value);
34534 - array_insert_unique(con->response.headers, (data_unset *)ds);
34536 - switch(key_len) {
34538 - if (0 == strncasecmp(key, "Date", key_len)) {
34539 - con->parsed_response |= HTTP_DATE;
34543 - if (0 == strncasecmp(key, "Status", key_len)) {
34544 - con->http_status = strtol(value, NULL, 10);
34545 - con->parsed_response |= HTTP_STATUS;
34549 - if (0 == strncasecmp(key, "Location", key_len)) {
34550 - con->parsed_response |= HTTP_LOCATION;
34554 - if (0 == strncasecmp(key, "Connection", key_len)) {
34555 - con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
34556 - con->parsed_response |= HTTP_CONNECTION;
34560 - if (0 == strncasecmp(key, "Content-Length", key_len)) {
34561 - con->response.content_length = strtol(value, NULL, 10);
34562 - con->parsed_response |= HTTP_CONTENT_LENGTH;
34571 - /* CGI/1.1 rev 03 - 7.2.1.2 */
34572 - if ((con->parsed_response & HTTP_LOCATION) &&
34573 - !(con->parsed_response & HTTP_STATUS)) {
34574 - con->http_status = 302;
34581 static int scgi_demux_response(server *srv, handler_ctx *hctx) {
34582 plugin_data *p = hctx->plugin_data;
34583 connection *con = hctx->remote_conn;
34588 - buffer_prepare_copy(hctx->response, 1024);
34589 - if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
34590 - if (errno == EAGAIN || errno == EINTR) {
34591 - /* would block, wait for signal */
34595 - log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
34600 - /* read finished */
34602 - con->file_finished = 1;
34604 - /* send final chunk */
34605 - http_chunk_append_mem(srv, con, NULL, 0);
34606 - joblist_append(srv, con);
34610 + switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
34611 + case NETWORK_STATUS_SUCCESS:
34612 + /* we got content */
34614 + case NETWORK_STATUS_WAIT_FOR_EVENT:
34615 + /* the ioctl will return WAIT_FOR_EVENT on a read */
34616 + if (0 == con->file_started) return -1;
34617 + case NETWORK_STATUS_CONNECTION_CLOSE:
34618 + /* we are done, get out of here */
34619 + con->file_finished = 1;
34621 + /* close the chunk-queue with a empty chunk */
34629 + /* looks like we got some content
34631 + * split off the header from the incoming stream
34634 + if (hctx->state == SCGI_STATE_RESPONSE_HEADER) {
34636 + int have_content_length = 0;
34638 + http_response_reset(p->resp);
34640 + /* the response header is not fully received yet,
34642 + * extract the http-response header from the rb-cq
34644 + switch (http_response_parse_cq(hctx->rb, p->resp)) {
34645 + case PARSE_ERROR:
34646 + /* parsing failed */
34648 + con->http_status = 502; /* Bad Gateway */
34652 - hctx->response->ptr[n] = '\0';
34653 - hctx->response->used = n+1;
34655 - /* split header from body */
34657 - if (con->file_started == 0) {
34659 - int in_header = 0;
34660 - int header_end = 0;
34661 - int cp, eol = EOL_UNSET;
34664 - buffer_append_string_buffer(hctx->response_header, hctx->response);
34666 - /* nph (non-parsed headers) */
34667 - if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
34669 - /* search for the \r\n\r\n or \n\n in the string */
34670 - for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
34671 - if (*c == ':') in_header = 1;
34672 - else if (*c == '\n') {
34673 - if (in_header == 0) {
34674 - /* got a response without a response header */
34681 - if (eol == EOL_UNSET) eol = EOL_N;
34683 - if (*(c+1) == '\n') {
34688 - } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
34689 - if (in_header == 0) {
34690 - /* got a response without a response header */
34697 - if (eol == EOL_UNSET) eol = EOL_RN;
34700 - *(c+2) == '\r' &&
34701 - *(c+3) == '\n') {
34706 - /* skip the \n */
34710 + case PARSE_NEED_MORE:
34712 + case PARSE_SUCCESS:
34713 + con->http_status = p->resp->status;
34715 + chunkqueue_remove_finished_chunks(hctx->rb);
34717 + /* copy the http-headers */
34718 + for (i = 0; i < p->resp->headers->used; i++) {
34719 + const char *ign[] = { "Status", "Connection", NULL };
34723 + data_string *header = (data_string *)p->resp->headers->data[i];
34725 + /* some headers are ignored by default */
34726 + for (j = 0; ign[j]; j++) {
34727 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
34731 - if (header_end) {
34733 - /* no header, but a body */
34735 - if (con->request.http_version == HTTP_VERSION_1_1) {
34736 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34739 - http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
34740 - joblist_append(srv, con);
34742 - size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
34743 - size_t blen = hctx->response_header->used - hlen - 1;
34745 - /* a small hack: terminate after at the second \r */
34746 - hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
34747 - hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
34749 - /* parse the response header */
34750 - scgi_response_parse(srv, con, p, hctx->response_header, eol);
34752 - /* enable chunked-transfer-encoding */
34753 - if (con->request.http_version == HTTP_VERSION_1_1 &&
34754 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
34755 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34758 - if ((hctx->response->used != hlen) && blen > 0) {
34759 - http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
34760 - joblist_append(srv, con);
34762 + if (ign[j]) continue;
34764 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
34765 + /* CGI/1.1 rev 03 - 7.2.1.2 */
34766 + if (con->http_status == 0) con->http_status = 302;
34767 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
34768 + have_content_length = 1;
34771 - con->file_started = 1;
34772 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
34773 + ds = data_response_init();
34775 + buffer_copy_string_buffer(ds->key, header->key);
34776 + buffer_copy_string_buffer(ds->value, header->value);
34778 + array_insert_unique(con->response.headers, (data_unset *)ds);
34781 - http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
34782 - joblist_append(srv, con);
34784 + con->file_started = 1;
34786 + if (con->request.http_version == HTTP_VERSION_1_1 &&
34787 + !have_content_length) {
34788 + con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34791 + hctx->state = SCGI_STATE_RESPONSE_CONTENT;
34796 - log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
34801 + /* FIXME: pass the response-header to the other plugins to
34802 + * setup the filter-queue
34804 + * - use next-queue instead of con->write_queue
34807 + assert(hctx->state == SCGI_STATE_RESPONSE_CONTENT);
34809 + /* FIXME: if we have a content-length or chunked-encoding
34812 + * for now we wait for EOF on the socket */
34814 + /* copy the content to the next cq */
34815 + for (c = hctx->rb->first; c; c = c->next) {
34816 + http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
34818 + c->offset = c->mem->used - 1;
34821 + chunkqueue_remove_finished_chunks(hctx->rb);
34822 + joblist_append(srv, con);
34828 int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *proc) {
34834 - /* we have been the smallest of the current list
34835 - * and we want to insert the node sorted as soon
34837 + /* we have been the smallest of the current list
34838 + * and we want to insert the node sorted as soon
34851 /* nothing to sort, only one element */
34852 @@ -1909,9 +1771,9 @@
34854 for (p = proc; p->next && p->next->load < proc->load; p = p->next);
34856 - /* no need to move something
34857 + /* no need to move something
34864 @@ -1930,16 +1792,16 @@
34866 if (proc->prev) proc->prev->next = proc->next;
34867 if (proc->next) proc->next->prev = proc->prev;
34870 /* proc should be right of p */
34873 proc->next = p->next;
34875 if (p->next) p->next->prev = proc;
34878 for(p = host->first; p; p = p->next) {
34879 - log_error_write(srv, __FILE__, __LINE__, "dd",
34880 + log_error_write(srv, __FILE__, __LINE__, "dd",
34884 @@ -1951,21 +1813,21 @@
34886 int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *proc) {
34892 - /* we have been the smallest of the current list
34893 - * and we want to insert the node sorted as soon
34895 + /* we have been the smallest of the current list
34896 + * and we want to insert the node sorted as soon
34906 * the basic is idea is:
34907 - * - the last active scgi process should be still
34908 + * - the last active scgi process should be still
34909 * in ram and is not swapped out yet
34910 * - processes that are not reused will be killed
34911 * after some time by the trigger-handler
34912 @@ -1975,7 +1837,7 @@
34913 * ice-cold processes are propably unused since more
34914 * than 'unused-timeout', are swaped out and won't be
34915 * reused in the next seconds anyway.
34920 /* nothing to sort, only one element */
34921 @@ -1984,16 +1846,16 @@
34922 for (p = host->first; p != proc && p->load < proc->load; p = p->next);
34925 - /* no need to move something
34926 + /* no need to move something
34935 if (p == proc) return 0;
34938 /* we have to move left. If we are already the first element
34940 if (host->first == proc) return 0;
34941 @@ -2009,9 +1871,9 @@
34944 if (proc->prev == NULL) host->first = proc;
34947 for(p = host->first; p; p = p->next) {
34948 - log_error_write(srv, __FILE__, __LINE__, "dd",
34949 + log_error_write(srv, __FILE__, __LINE__, "dd",
34953 @@ -2023,41 +1885,42 @@
34955 static int scgi_restart_dead_procs(server *srv, plugin_data *p, scgi_extension_host *host) {
34959 for (proc = host->first; proc; proc = proc->next) {
34960 if (p->conf.debug) {
34961 - log_error_write(srv, __FILE__, __LINE__, "sbdbdddd",
34963 - host->host, proc->port,
34964 + log_error_write(srv, __FILE__, __LINE__, "sbdbdddd",
34966 + host->host, proc->port,
34975 if (0 == proc->is_local) {
34977 - * external servers might get disabled
34979 - * enable the server again, perhaps it is back again
34981 + * external servers might get disabled
34983 + * enable the server again, perhaps it is back again
34987 if ((proc->state == PROC_STATE_DISABLED) &&
34988 (srv->cur_ts - proc->disable_ts > host->disable_time)) {
34989 proc->state = PROC_STATE_RUNNING;
34990 host->active_procs++;
34992 - log_error_write(srv, __FILE__, __LINE__, "sbdb",
34993 - "fcgi-server re-enabled:",
34994 - host->host, host->port,
34996 + log_error_write(srv, __FILE__, __LINE__, "sbdb",
34997 + "fcgi-server re-enabled:",
34998 + host->host, host->port,
35002 /* the child should not terminate at all */
35006 if (proc->state == PROC_STATE_DIED_WAIT_FOR_PID) {
35008 switch(waitpid(proc->pid, &status, WNOHANG)) {
35010 /* child is still alive */
35011 @@ -2067,33 +1930,34 @@
35013 if (WIFEXITED(status)) {
35015 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
35016 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
35017 "child exited, pid:", proc->pid,
35018 "status:", WEXITSTATUS(status));
35020 } else if (WIFSIGNALED(status)) {
35021 - log_error_write(srv, __FILE__, __LINE__, "sd",
35022 - "child signaled:",
35023 + log_error_write(srv, __FILE__, __LINE__, "sd",
35024 + "child signaled:",
35027 - log_error_write(srv, __FILE__, __LINE__, "sd",
35028 - "child died somehow:",
35029 + log_error_write(srv, __FILE__, __LINE__, "sd",
35030 + "child died somehow:",
35035 proc->state = PROC_STATE_DIED;
35044 * local servers might died, but we restart them
35048 if (proc->state == PROC_STATE_DIED &&
35050 /* restart the child */
35053 if (p->conf.debug) {
35054 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
35055 "--- scgi spawning",
35056 @@ -2101,18 +1965,18 @@
35057 "\n\tsocket", host->unixsocket,
35058 "\n\tcurrent:", 1, "/", host->min_procs);
35062 if (scgi_spawn_connection(srv, p, host, proc)) {
35063 log_error_write(srv, __FILE__, __LINE__, "s",
35064 "ERROR: spawning fcgi failed.");
35065 return HANDLER_ERROR;
35069 scgi_proclist_sort_down(srv, host, proc);
35078 @@ -2121,13 +1985,13 @@
35079 plugin_data *p = hctx->plugin_data;
35080 scgi_extension_host *host= hctx->host;
35081 connection *con = hctx->remote_conn;
35086 - /* sanity check */
35087 + /* sanity check */
35089 ((!host->host->used || !host->port) && !host->unixsocket->used)) {
35090 - log_error_write(srv, __FILE__, __LINE__, "sxddd",
35091 + log_error_write(srv, __FILE__, __LINE__, "sxddd",
35092 "write-req: error",
35095 @@ -2135,259 +1999,260 @@
35096 host->unixsocket->used);
35097 return HANDLER_ERROR;
35102 switch(hctx->state) {
35103 - case FCGI_STATE_INIT:
35104 + case SCGI_STATE_INIT:
35105 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
35107 - if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
35109 + if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
35110 if (errno == EMFILE ||
35112 - log_error_write(srv, __FILE__, __LINE__, "sd",
35113 - "wait for fd at connection:", con->fd);
35115 + log_error_write(srv, __FILE__, __LINE__, "sd",
35116 + "wait for fd at connection:", con->sock->fd);
35118 return HANDLER_WAIT_FOR_FD;
35121 - log_error_write(srv, __FILE__, __LINE__, "ssdd",
35123 + log_error_write(srv, __FILE__, __LINE__, "ssdd",
35124 "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
35125 return HANDLER_ERROR;
35127 - hctx->fde_ndx = -1;
35129 + hctx->sock->fde_ndx = -1;
35133 - fdevent_register(srv->ev, hctx->fd, scgi_handle_fdevent, hctx);
35135 - if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
35136 - log_error_write(srv, __FILE__, __LINE__, "ss",
35138 + fdevent_register(srv->ev, hctx->sock, scgi_handle_fdevent, hctx);
35140 + if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
35141 + log_error_write(srv, __FILE__, __LINE__, "ss",
35142 "fcntl failed: ", strerror(errno));
35145 return HANDLER_ERROR;
35150 - case FCGI_STATE_CONNECT:
35151 - if (hctx->state == FCGI_STATE_INIT) {
35152 - for (hctx->proc = hctx->host->first;
35153 - hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
35154 + case SCGI_STATE_CONNECT:
35155 + if (hctx->state == SCGI_STATE_INIT) {
35156 + for (hctx->proc = hctx->host->first;
35157 + hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
35158 hctx->proc = hctx->proc->next);
35161 /* all childs are dead */
35162 if (hctx->proc == NULL) {
35163 - hctx->fde_ndx = -1;
35165 + hctx->sock->fde_ndx = -1;
35167 return HANDLER_ERROR;
35171 if (hctx->proc->is_local) {
35172 hctx->pid = hctx->proc->pid;
35176 switch (scgi_establish_connection(srv, hctx)) {
35178 - scgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
35180 + scgi_set_state(srv, hctx, SCGI_STATE_CONNECT);
35182 /* connection is in progress, wait for an event and call getsockopt() below */
35184 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35187 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35189 return HANDLER_WAIT_FOR_EVENT;
35191 /* if ECONNREFUSED choose another connection -> FIXME */
35192 - hctx->fde_ndx = -1;
35194 + hctx->sock->fde_ndx = -1;
35196 return HANDLER_ERROR;
35198 /* everything is ok, go on */
35206 socklen_t socket_error_len = sizeof(socket_error);
35209 /* try to finish the connect() */
35210 - if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
35211 - log_error_write(srv, __FILE__, __LINE__, "ss",
35212 + if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
35213 + log_error_write(srv, __FILE__, __LINE__, "ss",
35214 "getsockopt failed:", strerror(errno));
35217 return HANDLER_ERROR;
35219 if (socket_error != 0) {
35220 if (!hctx->proc->is_local || p->conf.debug) {
35221 /* local procs get restarted */
35224 log_error_write(srv, __FILE__, __LINE__, "ss",
35225 - "establishing connection failed:", strerror(socket_error),
35226 + "establishing connection failed:", strerror(socket_error),
35227 "port:", hctx->proc->port);
35231 return HANDLER_ERROR;
35236 /* ok, we have the connection */
35239 hctx->proc->load++;
35240 hctx->proc->last_used = srv->cur_ts;
35241 hctx->got_proc = 1;
35244 if (p->conf.debug) {
35245 log_error_write(srv, __FILE__, __LINE__, "sddbdd",
35249 - hctx->proc->socket,
35253 + hctx->proc->socket,
35258 /* move the proc-list entry down the list */
35259 scgi_proclist_sort_up(srv, hctx->host, hctx->proc);
35261 - scgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
35263 + scgi_set_state(srv, hctx, SCGI_STATE_PREPARE_WRITE);
35265 - case FCGI_STATE_PREPARE_WRITE:
35266 + case SCGI_STATE_PREPARE_WRITE:
35267 scgi_create_env(srv, hctx);
35269 - scgi_set_state(srv, hctx, FCGI_STATE_WRITE);
35272 + scgi_set_state(srv, hctx, SCGI_STATE_WRITE);
35275 - case FCGI_STATE_WRITE:
35276 - ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
35277 + case SCGI_STATE_WRITE:
35278 + ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
35280 chunkqueue_remove_finished_chunks(hctx->wb);
35284 if (errno == ENOTCONN) {
35285 - /* the connection got dropped after accept()
35287 - * this is most of the time a PHP which dies
35288 + /* the connection got dropped after accept()
35290 + * this is most of the time a PHP which dies
35291 * after PHP_FCGI_MAX_REQUESTS
35296 if (hctx->wb->bytes_out == 0 &&
35297 hctx->reconnects < 5) {
35298 - usleep(10000); /* take away the load of the webserver
35299 - * to let the php a chance to restart
35301 + usleep(10000); /* take away the load of the webserver
35302 + * to let the php a chance to restart
35306 scgi_reconnect(srv, hctx);
35309 return HANDLER_WAIT_FOR_FD;
35313 /* not reconnected ... why
35316 * far@#lighttpd report this for FreeBSD
35321 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35323 + log_error_write(srv, __FILE__, __LINE__, "ssosd",
35324 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
35325 "write-offset:", hctx->wb->bytes_out,
35326 "reconnect attempts:", hctx->reconnects);
35329 return HANDLER_ERROR;
35333 if ((errno != EAGAIN) &&
35334 (errno != EINTR)) {
35336 - log_error_write(srv, __FILE__, __LINE__, "ssd",
35338 + log_error_write(srv, __FILE__, __LINE__, "ssd",
35339 "write failed:", strerror(errno), errno);
35342 return HANDLER_ERROR;
35344 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35346 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35348 return HANDLER_WAIT_FOR_EVENT;
35353 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
35354 /* we don't need the out event anymore */
35355 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
35356 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
35357 - scgi_set_state(srv, hctx, FCGI_STATE_READ);
35358 + fdevent_event_del(srv->ev, hctx->sock);
35359 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
35360 + scgi_set_state(srv, hctx, SCGI_STATE_RESPONSE_HEADER);
35362 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35364 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35366 return HANDLER_WAIT_FOR_EVENT;
35371 - case FCGI_STATE_READ:
35372 + case SCGI_STATE_RESPONSE_HEADER:
35373 /* waiting for a response */
35376 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
35377 return HANDLER_ERROR;
35381 return HANDLER_WAIT_FOR_EVENT;
35384 SUBREQUEST_FUNC(mod_scgi_handle_subrequest) {
35385 plugin_data *p = p_d;
35388 handler_ctx *hctx = con->plugin_ctx[p->id];
35390 scgi_extension_host *host;
35393 if (NULL == hctx) return HANDLER_GO_ON;
35397 if (con->mode != p->id) return HANDLER_GO_ON;
35400 /* ok, create the request */
35401 switch(scgi_write_request(srv, hctx)) {
35402 case HANDLER_ERROR:
35409 0 == proc->is_local &&
35410 proc->state != PROC_STATE_DISABLED) {
35411 /* only disable remote servers as we don't manage them*/
35413 - log_error_write(srv, __FILE__, __LINE__, "sbdb", "fcgi-server disabled:",
35415 + log_error_write(srv, __FILE__, __LINE__, "sbdb", "fcgi-server disabled:",
35421 /* disable this server */
35422 proc->disable_ts = srv->cur_ts;
35423 proc->state = PROC_STATE_DISABLED;
35424 host->active_procs--;
35427 - if (hctx->state == FCGI_STATE_INIT ||
35428 - hctx->state == FCGI_STATE_CONNECT) {
35429 - /* connect() or getsockopt() failed,
35430 - * restart the request-handling
35432 + if (hctx->state == SCGI_STATE_INIT ||
35433 + hctx->state == SCGI_STATE_CONNECT) {
35434 + /* connect() or getsockopt() failed,
35435 + * restart the request-handling
35437 if (proc && proc->is_local) {
35439 if (p->conf.debug) {
35440 - log_error_write(srv, __FILE__, __LINE__, "sbdb", "connect() to scgi failed, restarting the request-handling:",
35441 + log_error_write(srv, __FILE__, __LINE__, "sbdb", "connect() to scgi failed, restarting the request-handling:",
35449 * several hctx might reference the same proc
35452 * Only one of them should mark the proc as dead all the other
35453 * ones should just take a new one.
35456 * If a new proc was started with the old struct this might lead
35457 * the mark a perfect proc as dead otherwise
35461 if (proc->state == PROC_STATE_RUNNING &&
35462 hctx->pid == proc->pid) {
35463 @@ -2395,25 +2260,25 @@
35466 scgi_restart_dead_procs(srv, p, host);
35469 scgi_connection_cleanup(srv, hctx);
35472 buffer_reset(con->physical.path);
35473 con->mode = DIRECT;
35474 joblist_append(srv, con);
35476 - /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
35477 - * and hope that the childs will be restarted
35480 + /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
35481 + * and hope that the childs will be restarted
35484 return HANDLER_WAIT_FOR_FD;
35486 scgi_connection_cleanup(srv, hctx);
35489 buffer_reset(con->physical.path);
35490 con->mode = DIRECT;
35491 con->http_status = 503;
35494 return HANDLER_FINISHED;
35496 case HANDLER_WAIT_FOR_EVENT:
35497 @@ -2433,23 +2298,23 @@
35498 static handler_t scgi_connection_close(server *srv, handler_ctx *hctx) {
35503 if (NULL == hctx) return HANDLER_GO_ON;
35506 p = hctx->plugin_data;
35507 con = hctx->remote_conn;
35510 if (con->mode != p->id) return HANDLER_GO_ON;
35512 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35513 - "emergency exit: scgi:",
35514 - "connection-fd:", con->fd,
35515 - "fcgi-fd:", hctx->fd);
35520 + log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35521 + "emergency exit: scgi:",
35522 + "connection-fd:", con->sock->fd,
35523 + "fcgi-fd:", hctx->sock->fd);
35527 scgi_connection_cleanup(srv, hctx);
35530 return HANDLER_FINISHED;
35533 @@ -2459,27 +2324,28 @@
35534 handler_ctx *hctx = ctx;
35535 connection *con = hctx->remote_conn;
35536 plugin_data *p = hctx->plugin_data;
35539 scgi_proc *proc = hctx->proc;
35540 scgi_extension_host *host= hctx->host;
35542 if ((revents & FDEVENT_IN) &&
35543 - hctx->state == FCGI_STATE_READ) {
35544 + (hctx->state == SCGI_STATE_RESPONSE_HEADER ||
35545 + hctx->state == SCGI_STATE_RESPONSE_CONTENT)) {
35546 switch (scgi_demux_response(srv, hctx)) {
35551 scgi_connection_cleanup(srv, hctx);
35554 joblist_append(srv, con);
35555 return HANDLER_FINISHED;
35557 if (proc->pid && proc->state != PROC_STATE_DIED) {
35561 /* only fetch the zombie if it is not already done */
35564 switch(waitpid(proc->pid, &status, WNOHANG)) {
35566 /* child is still alive */
35567 @@ -2489,19 +2355,19 @@
35569 /* the child should not terminate at all */
35570 if (WIFEXITED(status)) {
35571 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
35572 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
35573 "child exited, pid:", proc->pid,
35574 "status:", WEXITSTATUS(status));
35575 } else if (WIFSIGNALED(status)) {
35576 - log_error_write(srv, __FILE__, __LINE__, "sd",
35577 - "child signaled:",
35578 + log_error_write(srv, __FILE__, __LINE__, "sd",
35579 + "child signaled:",
35582 - log_error_write(srv, __FILE__, __LINE__, "sd",
35583 - "child died somehow:",
35584 + log_error_write(srv, __FILE__, __LINE__, "sd",
35585 + "child died somehow:",
35590 if (p->conf.debug) {
35591 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
35592 "--- scgi spawning",
35593 @@ -2509,40 +2375,41 @@
35594 "\n\tsocket", host->unixsocket,
35595 "\n\tcurrent:", 1, "/", host->min_procs);
35599 if (scgi_spawn_connection(srv, p, host, proc)) {
35601 proc->state = PROC_STATE_DIED;
35603 scgi_proclist_sort_down(srv, host, proc);
35612 if (con->file_started == 0) {
35613 /* nothing has been send out yet, try to use another child */
35616 if (hctx->wb->bytes_out == 0 &&
35617 hctx->reconnects < 5) {
35618 scgi_reconnect(srv, hctx);
35620 - log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
35622 + log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
35623 "response not sent, request not sent, reconnection.",
35624 - "connection-fd:", con->fd,
35625 - "fcgi-fd:", hctx->fd);
35627 + "connection-fd:", con->sock->fd,
35628 + "fcgi-fd:", hctx->sock->fd);
35630 return HANDLER_WAIT_FOR_FD;
35633 - log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
35635 + log_error_write(srv, __FILE__, __LINE__, "sosdsd",
35636 "response not sent, request sent:", hctx->wb->bytes_out,
35637 - "connection-fd:", con->fd,
35638 - "fcgi-fd:", hctx->fd);
35640 + "connection-fd:", con->sock->fd,
35641 + "fcgi-fd:", hctx->sock->fd);
35643 scgi_connection_cleanup(srv, hctx);
35646 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
35647 buffer_reset(con->physical.path);
35648 con->http_status = 500;
35649 @@ -2550,76 +2417,77 @@
35651 /* response might have been already started, kill the connection */
35652 scgi_connection_cleanup(srv, hctx);
35654 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35656 + log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35657 "response already sent out, termination connection",
35658 - "connection-fd:", con->fd,
35659 - "fcgi-fd:", hctx->fd);
35661 + "connection-fd:", con->sock->fd,
35662 + "fcgi-fd:", hctx->sock->fd);
35664 connection_set_state(srv, con, CON_STATE_ERROR);
35672 joblist_append(srv, con);
35673 return HANDLER_FINISHED;
35678 if (revents & FDEVENT_OUT) {
35679 - if (hctx->state == FCGI_STATE_CONNECT ||
35680 - hctx->state == FCGI_STATE_WRITE) {
35681 + if (hctx->state == SCGI_STATE_CONNECT ||
35682 + hctx->state == SCGI_STATE_WRITE) {
35683 /* we are allowed to send something out
35686 * 1. in a unfinished connect() call
35687 * 2. in a unfinished write() call (long POST request)
35689 return mod_scgi_handle_subrequest(srv, con, p);
35691 - log_error_write(srv, __FILE__, __LINE__, "sd",
35692 - "got a FDEVENT_OUT and didn't know why:",
35693 + log_error_write(srv, __FILE__, __LINE__, "sd",
35694 + "got a FDEVENT_OUT and didn't know why:",
35700 /* perhaps this issue is already handled */
35701 if (revents & FDEVENT_HUP) {
35702 - if (hctx->state == FCGI_STATE_CONNECT) {
35703 + if (hctx->state == SCGI_STATE_CONNECT) {
35704 /* getoptsock will catch this one (right ?)
35706 - * if we are in connect we might get a EINPROGRESS
35707 - * in the first call and a FDEVENT_HUP in the
35709 + * if we are in connect we might get a EINPROGRESS
35710 + * in the first call and a FDEVENT_HUP in the
35714 * FIXME: as it is a bit ugly.
35718 return mod_scgi_handle_subrequest(srv, con, p);
35719 - } else if (hctx->state == FCGI_STATE_READ &&
35720 + } else if ((hctx->state == SCGI_STATE_RESPONSE_HEADER ||
35721 + hctx->state == SCGI_STATE_RESPONSE_CONTENT ) &&
35722 hctx->proc->port == 0) {
35726 * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
35727 * even if the FCGI_FIN packet is not received yet
35730 - log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
35731 - "error: unexpected close of scgi connection for",
35732 + log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
35733 + "error: unexpected close of scgi connection for",
35735 - "(no scgi process on host: ",
35736 + "(no scgi process on host: ",
35745 connection_set_state(srv, con, CON_STATE_ERROR);
35746 scgi_connection_close(srv, hctx);
35747 joblist_append(srv, con);
35749 } else if (revents & FDEVENT_ERR) {
35750 - log_error_write(srv, __FILE__, __LINE__, "s",
35751 + log_error_write(srv, __FILE__, __LINE__, "s",
35752 "fcgi: got a FDEVENT_ERR. Don't know why.");
35753 /* kill all connections to the scgi process */
35755 @@ -2628,42 +2496,39 @@
35756 scgi_connection_close(srv, hctx);
35757 joblist_append(srv, con);
35761 return HANDLER_FINISHED;
35763 -#define PATCH(x) \
35764 - p->conf.x = s->x;
35766 static int scgi_patch_connection(server *srv, connection *con, plugin_data *p) {
35768 plugin_config *s = p->config_storage[0];
35774 + PATCH_OPTION(exts);
35775 + PATCH_OPTION(debug);
35777 /* skip the first, the global context */
35778 for (i = 1; i < srv->config_context->used; i++) {
35779 data_config *dc = (data_config *)srv->config_context->data[i];
35780 s = p->config_storage[i];
35783 /* condition didn't match */
35784 if (!config_check_cond(srv, con, dc)) continue;
35788 for (j = 0; j < dc->value->used; j++) {
35789 data_unset *du = dc->value->data[j];
35792 if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.server"))) {
35794 + PATCH_OPTION(exts);
35795 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.debug"))) {
35797 + PATCH_OPTION(debug);
35808 static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
35809 plugin_data *p = p_d;
35810 @@ -2673,30 +2538,30 @@
35813 scgi_extension *extension = NULL;
35816 /* Possibly, we processed already this request */
35817 if (con->file_started == 1) return HANDLER_GO_ON;
35820 fn = uri_path_handler ? con->uri.path : con->physical.path;
35822 if (buffer_is_empty(fn)) return HANDLER_GO_ON;
35824 s_len = fn->used - 1;
35827 scgi_patch_connection(srv, con, p);
35829 /* check if extension matches */
35830 for (k = 0; k < p->conf.exts->used; k++) {
35834 extension = p->conf.exts->exts[k];
35837 if (extension->key->used == 0) continue;
35840 ct_len = extension->key->used - 1;
35843 if (s_len < ct_len) continue;
35846 /* check extension in the form "/scgi_pattern" */
35847 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
35849 @@ -2710,17 +2575,17 @@
35850 if (k == p->conf.exts->used) {
35851 return HANDLER_GO_ON;
35855 /* get best server */
35856 for (k = 0, ndx = -1; k < extension->used; k++) {
35857 scgi_extension_host *host = extension->hosts[k];
35860 /* we should have at least one proc that can do somthing */
35861 if (host->active_procs == 0) continue;
35863 if (used == -1 || host->load < used) {
35870 @@ -2728,12 +2593,12 @@
35871 /* found a server */
35873 scgi_extension_host *host = extension->hosts[ndx];
35876 - * if check-local is disabled, use the uri.path handler
35880 + * if check-local is disabled, use the uri.path handler
35885 /* init handler-context */
35886 if (uri_path_handler) {
35887 if (host->check_local == 0) {
35888 @@ -2741,7 +2606,7 @@
35891 hctx = handler_ctx_init();
35894 hctx->remote_conn = con;
35895 hctx->plugin_data = p;
35897 @@ -2749,45 +2614,45 @@
35899 hctx->conf.exts = p->conf.exts;
35900 hctx->conf.debug = p->conf.debug;
35903 con->plugin_ctx[p->id] = hctx;
35911 if (con->conf.log_request_handling) {
35912 log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_scgi");
35915 - /* the prefix is the SCRIPT_NAME,
35916 + /* the prefix is the SCRIPT_NAME,
35917 * everthing from start to the next slash
35918 * this is important for check-local = "disable"
35921 * if prefix = /admin.fcgi
35924 * /admin.fcgi/foo/bar
35927 * SCRIPT_NAME = /admin.fcgi
35928 * PATH_INFO = /foo/bar
35931 * if prefix = /fcgi-bin/
35934 * /fcgi-bin/foo/bar
35937 * SCRIPT_NAME = /fcgi-bin/foo
35944 /* the rewrite is only done for /prefix/? matches */
35945 if (extension->key->ptr[0] == '/' &&
35946 con->uri.path->used > extension->key->used &&
35947 NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
35948 - /* rewrite uri.path and pathinfo */
35950 + /* rewrite uri.path and pathinfo */
35952 buffer_copy_string(con->request.pathinfo, pathinfo);
35955 con->uri.path->used -= con->request.pathinfo->used - 1;
35956 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
35958 @@ -2796,21 +2661,21 @@
35961 hctx = handler_ctx_init();
35964 hctx->remote_conn = con;
35965 hctx->plugin_data = p;
35970 hctx->conf.exts = p->conf.exts;
35971 hctx->conf.debug = p->conf.debug;
35974 con->plugin_ctx[p->id] = hctx;
35983 if (con->conf.log_request_handling) {
35984 log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
35986 @@ -2821,11 +2686,11 @@
35987 /* no handler found */
35988 buffer_reset(con->physical.path);
35989 con->http_status = 500;
35991 - log_error_write(srv, __FILE__, __LINE__, "sb",
35992 - "no fcgi-handler found for:",
35994 + log_error_write(srv, __FILE__, __LINE__, "sb",
35995 + "no fcgi-handler found for:",
35999 return HANDLER_FINISHED;
36001 return HANDLER_GO_ON;
36002 @@ -2844,21 +2709,22 @@
36003 JOBLIST_FUNC(mod_scgi_handle_joblist) {
36004 plugin_data *p = p_d;
36005 handler_ctx *hctx = con->plugin_ctx[p->id];
36008 if (hctx == NULL) return HANDLER_GO_ON;
36010 - if (hctx->fd != -1) {
36011 + if (hctx->sock->fd != -1) {
36012 switch (hctx->state) {
36013 - case FCGI_STATE_READ:
36014 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
36016 + case SCGI_STATE_RESPONSE_HEADER:
36017 + case SCGI_STATE_RESPONSE_CONTENT:
36018 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
36021 - case FCGI_STATE_CONNECT:
36022 - case FCGI_STATE_WRITE:
36023 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
36025 + case SCGI_STATE_CONNECT:
36026 + case SCGI_STATE_WRITE:
36027 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
36030 - case FCGI_STATE_INIT:
36031 + case SCGI_STATE_INIT:
36035 @@ -2873,21 +2739,21 @@
36037 static handler_t scgi_connection_close_callback(server *srv, connection *con, void *p_d) {
36038 plugin_data *p = p_d;
36041 return scgi_connection_close(srv, con->plugin_ctx[p->id]);
36044 TRIGGER_FUNC(mod_scgi_handle_trigger) {
36045 plugin_data *p = p_d;
36051 /* perhaps we should kill a connect attempt after 10-15 seconds
36054 * currently we wait for the TCP timeout which is on Linux 180 seconds
36063 /* check all childs if they are still up */
36064 @@ -2904,47 +2770,47 @@
36065 scgi_extension *ex;
36067 ex = exts->exts[j];
36070 for (n = 0; n < ex->used; n++) {
36074 unsigned long sum_load = 0;
36075 scgi_extension_host *host;
36078 host = ex->hosts[n];
36081 scgi_restart_dead_procs(srv, p, host);
36084 for (proc = host->first; proc; proc = proc->next) {
36085 sum_load += proc->load;
36089 if (host->num_procs &&
36090 host->num_procs < host->max_procs &&
36091 (sum_load / host->num_procs) > host->max_load_per_proc) {
36092 /* overload, spawn new child */
36093 scgi_proc *fp = NULL;
36096 if (p->conf.debug) {
36097 - log_error_write(srv, __FILE__, __LINE__, "s",
36098 + log_error_write(srv, __FILE__, __LINE__, "s",
36099 "overload detected, spawning a new child");
36103 for (fp = host->unused_procs; fp && fp->pid != 0; fp = fp->next);
36107 if (fp == host->unused_procs) host->unused_procs = fp->next;
36110 if (fp->next) fp->next->prev = NULL;
36115 fp = scgi_process_init();
36116 fp->id = host->max_id++;
36123 if (buffer_is_empty(host->unixsocket)) {
36124 fp->port = host->port + fp->id;
36126 @@ -2952,13 +2818,13 @@
36127 buffer_append_string(fp->socket, "-");
36128 buffer_append_long(fp->socket, fp->id);
36132 if (scgi_spawn_connection(srv, p, host, fp)) {
36133 log_error_write(srv, __FILE__, __LINE__, "s",
36134 "ERROR: spawning fcgi failed.");
36135 return HANDLER_ERROR;
36140 fp->next = host->first;
36142 @@ -2966,56 +2832,57 @@
36148 for (proc = host->first; proc; proc = proc->next) {
36149 if (proc->load != 0) break;
36150 if (host->num_procs <= host->min_procs) break;
36151 if (proc->pid == 0) continue;
36154 if (srv->cur_ts - proc->last_used > host->idle_timeout) {
36155 /* a proc is idling for a long time now,
36159 if (p->conf.debug) {
36160 - log_error_write(srv, __FILE__, __LINE__, "ssbsd",
36161 - "idle-timeout reached, terminating child:",
36162 - "socket:", proc->socket,
36163 + log_error_write(srv, __FILE__, __LINE__, "ssbsd",
36164 + "idle-timeout reached, terminating child:",
36165 + "socket:", proc->socket,
36172 if (proc->next) proc->next->prev = proc->prev;
36173 if (proc->prev) proc->prev->next = proc->next;
36176 if (proc->prev == NULL) host->first = proc->next;
36180 proc->next = host->unused_procs;
36183 if (host->unused_procs) host->unused_procs->prev = proc;
36184 host->unused_procs = proc;
36187 kill(proc->pid, SIGTERM);
36190 proc->state = PROC_STATE_KILLED;
36192 - log_error_write(srv, __FILE__, __LINE__, "ssbsd",
36194 - "socket:", proc->socket,
36196 + log_error_write(srv, __FILE__, __LINE__, "ssbsd",
36198 + "socket:", proc->socket,
36205 /* proc is now in unused, let the next second handle the next process */
36213 for (proc = host->unused_procs; proc; proc = proc->next) {
36217 if (proc->pid == 0) continue;
36220 switch (waitpid(proc->pid, &status, WNOHANG)) {
36222 /* child still running after timeout, good */
36223 @@ -3023,10 +2890,10 @@
36225 if (errno != EINTR) {
36226 /* no PID found ? should never happen */
36227 - log_error_write(srv, __FILE__, __LINE__, "sddss",
36228 + log_error_write(srv, __FILE__, __LINE__, "sddss",
36229 "pid ", proc->pid, proc->state,
36230 "not found:", strerror(errno));
36234 if (errno == ECHILD) {
36235 /* someone else has cleaned up for us */
36236 @@ -3040,25 +2907,26 @@
36237 /* the child should not terminate at all */
36238 if (WIFEXITED(status)) {
36239 if (proc->state != PROC_STATE_KILLED) {
36240 - log_error_write(srv, __FILE__, __LINE__, "sdb",
36242 + log_error_write(srv, __FILE__, __LINE__, "sdb",
36244 WEXITSTATUS(status), proc->socket);
36246 } else if (WIFSIGNALED(status)) {
36247 if (WTERMSIG(status) != SIGTERM) {
36248 - log_error_write(srv, __FILE__, __LINE__, "sd",
36249 - "child signaled:",
36250 + log_error_write(srv, __FILE__, __LINE__, "sd",
36251 + "child signaled:",
36255 - log_error_write(srv, __FILE__, __LINE__, "sd",
36256 - "child died somehow:",
36257 + log_error_write(srv, __FILE__, __LINE__, "sd",
36258 + "child died somehow:",
36262 proc->state = PROC_STATE_UNSET;
36269 @@ -3082,8 +2950,8 @@
36270 p->handle_subrequest = mod_scgi_handle_subrequest;
36271 p->handle_joblist = mod_scgi_handle_joblist;
36272 p->handle_trigger = mod_scgi_handle_trigger;
36280 --- ../lighttpd-1.4.11/src/mod_secure_download.c 2005-12-14 14:37:29.000000000 +0200
36281 +++ lighttpd-1.4.12/src/mod_secure_download.c 2006-07-16 00:26:03.000000000 +0300
36291 @@ -36,28 +36,28 @@
36294 buffer *uri_prefix;
36297 unsigned short timeout;
36307 plugin_config **config_storage;
36309 - plugin_config conf;
36311 + plugin_config conf;
36314 /* init the plugin data */
36315 INIT_FUNC(mod_secdownload_init) {
36319 p = calloc(1, sizeof(*p));
36322 p->md5 = buffer_init();
36328 @@ -65,27 +65,27 @@
36329 FREE_FUNC(mod_secdownload_free) {
36330 plugin_data *p = p_d;
36334 if (!p) return HANDLER_GO_ON;
36337 if (p->config_storage) {
36339 for (i = 0; i < srv->config_context->used; i++) {
36340 plugin_config *s = p->config_storage[i];
36343 buffer_free(s->secret);
36344 buffer_free(s->doc_root);
36345 buffer_free(s->uri_prefix);
36350 free(p->config_storage);
36354 buffer_free(p->md5);
36360 return HANDLER_GO_ON;
36363 @@ -94,107 +94,103 @@
36364 SETDEFAULTS_FUNC(mod_secdownload_set_defaults) {
36365 plugin_data *p = p_d;
36368 - config_values_t cv[] = {
36370 + config_values_t cv[] = {
36371 { "secdownload.secret", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
36372 { "secdownload.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
36373 { "secdownload.uri-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
36374 { "secdownload.timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
36375 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36379 if (!p) return HANDLER_ERROR;
36382 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36385 for (i = 0; i < srv->config_context->used; i++) {
36389 s = calloc(1, sizeof(plugin_config));
36390 s->secret = buffer_init();
36391 s->doc_root = buffer_init();
36392 s->uri_prefix = buffer_init();
36396 cv[0].destination = s->secret;
36397 cv[1].destination = s->doc_root;
36398 cv[2].destination = s->uri_prefix;
36399 cv[3].destination = &(s->timeout);
36402 p->config_storage[i] = s;
36405 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
36406 return HANDLER_ERROR;
36411 return HANDLER_GO_ON;
36415 * checks if the supplied string is a MD5 string
36418 * @param str a possible MD5 string
36419 * @return if the supplied string is a valid MD5 string 1 is returned otherwise 0
36422 int is_hex_len(const char *str, size_t len) {
36426 if (NULL == str) return 0;
36429 for (i = 0; i < len && *str; i++, str++) {
36430 /* illegal characters */
36431 if (!((*str >= '0' && *str <= '9') ||
36432 (*str >= 'a' && *str <= 'f') ||
36433 - (*str >= 'A' && *str <= 'F'))
36434 + (*str >= 'A' && *str <= 'F'))
36444 -#define PATCH(x) \
36445 - p->conf.x = s->x;
36446 static int mod_secdownload_patch_connection(server *srv, connection *con, plugin_data *p) {
36448 plugin_config *s = p->config_storage[0];
36452 - PATCH(uri_prefix);
36456 + PATCH_OPTION(secret);
36457 + PATCH_OPTION(doc_root);
36458 + PATCH_OPTION(uri_prefix);
36459 + PATCH_OPTION(timeout);
36461 /* skip the first, the global context */
36462 for (i = 1; i < srv->config_context->used; i++) {
36463 data_config *dc = (data_config *)srv->config_context->data[i];
36464 s = p->config_storage[i];
36467 /* condition didn't match */
36468 if (!config_check_cond(srv, con, dc)) continue;
36472 for (j = 0; j < dc->value->used; j++) {
36473 data_unset *du = dc->value->data[j];
36476 if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.secret"))) {
36478 + PATCH_OPTION(secret);
36479 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.document-root"))) {
36481 + PATCH_OPTION(doc_root);
36482 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.uri-prefix"))) {
36483 - PATCH(uri_prefix);
36484 + PATCH_OPTION(uri_prefix);
36485 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.timeout"))) {
36487 + PATCH_OPTION(timeout);
36498 URIHANDLER_FUNC(mod_secdownload_uri_handler) {
36499 plugin_data *p = p_d;
36500 @@ -203,88 +199,88 @@
36501 const char *rel_uri, *ts_str, *md5_str;
36506 if (con->uri.path->used == 0) return HANDLER_GO_ON;
36509 mod_secdownload_patch_connection(srv, con, p);
36511 if (buffer_is_empty(p->conf.uri_prefix)) return HANDLER_GO_ON;
36514 if (buffer_is_empty(p->conf.secret)) {
36515 log_error_write(srv, __FILE__, __LINE__, "s",
36516 "secdownload.secret has to be set");
36517 return HANDLER_ERROR;
36521 if (buffer_is_empty(p->conf.doc_root)) {
36522 log_error_write(srv, __FILE__, __LINE__, "s",
36523 "secdownload.document-root has to be set");
36524 return HANDLER_ERROR;
36530 * /<uri-prefix>[a-f0-9]{32}/[a-f0-9]{8}/<rel-path>
36534 if (0 != strncmp(con->uri.path->ptr, p->conf.uri_prefix->ptr, p->conf.uri_prefix->used - 1)) return HANDLER_GO_ON;
36537 md5_str = con->uri.path->ptr + p->conf.uri_prefix->used - 1;
36540 if (!is_hex_len(md5_str, 32)) return HANDLER_GO_ON;
36541 if (*(md5_str + 32) != '/') return HANDLER_GO_ON;
36544 ts_str = md5_str + 32 + 1;
36547 if (!is_hex_len(ts_str, 8)) return HANDLER_GO_ON;
36548 if (*(ts_str + 8) != '/') return HANDLER_GO_ON;
36551 for (i = 0; i < 8; i++) {
36552 ts = (ts << 4) + hex2int(*(ts_str + i));
36557 - if (srv->cur_ts - ts > p->conf.timeout ||
36558 + if (srv->cur_ts - ts > p->conf.timeout ||
36559 srv->cur_ts - ts < -p->conf.timeout) {
36560 con->http_status = 408;
36563 return HANDLER_FINISHED;
36567 rel_uri = ts_str + 8;
36574 * <secret><rel-path><timestamp-hex>
36578 buffer_copy_string_buffer(p->md5, p->conf.secret);
36579 buffer_append_string(p->md5, rel_uri);
36580 buffer_append_string_len(p->md5, ts_str, 8);
36584 MD5_Update(&Md5Ctx, (unsigned char *)p->md5->ptr, p->md5->used - 1);
36585 MD5_Final(HA1, &Md5Ctx);
36588 buffer_copy_string_hex(p->md5, (char *)HA1, 16);
36591 if (0 != strncmp(md5_str, p->md5->ptr, 32)) {
36592 con->http_status = 403;
36594 - log_error_write(srv, __FILE__, __LINE__, "sss",
36596 + log_error_write(srv, __FILE__, __LINE__, "sss",
36598 md5_str, p->md5->ptr);
36601 return HANDLER_FINISHED;
36605 /* starting with the last / we should have relative-path to the docroot
36609 buffer_copy_string_buffer(con->physical.doc_root, p->conf.doc_root);
36610 buffer_copy_string(con->physical.rel_path, rel_uri);
36611 buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
36612 buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
36615 return HANDLER_GO_ON;
36618 @@ -293,13 +289,13 @@
36619 int mod_secdownload_plugin_init(plugin *p) {
36620 p->version = LIGHTTPD_VERSION_ID;
36621 p->name = buffer_init_string("secdownload");
36624 p->init = mod_secdownload_init;
36625 p->handle_physical = mod_secdownload_uri_handler;
36626 p->set_defaults = mod_secdownload_set_defaults;
36627 p->cleanup = mod_secdownload_free;
36635 --- ../lighttpd-1.4.11/src/mod_setenv.c 2006-01-14 20:33:12.000000000 +0200
36636 +++ lighttpd-1.4.12/src/mod_setenv.c 2006-07-16 00:26:04.000000000 +0300
36637 @@ -18,25 +18,25 @@
36639 array *request_header;
36640 array *response_header;
36643 array *environment;
36650 plugin_config **config_storage;
36652 - plugin_config conf;
36654 + plugin_config conf;
36657 static handler_ctx * handler_ctx_init() {
36658 handler_ctx * hctx;
36661 hctx = calloc(1, sizeof(*hctx));
36670 @@ -48,36 +48,36 @@
36671 /* init the plugin data */
36672 INIT_FUNC(mod_setenv_init) {
36676 p = calloc(1, sizeof(*p));
36682 /* detroy the plugin data */
36683 FREE_FUNC(mod_setenv_free) {
36684 plugin_data *p = p_d;
36689 if (!p) return HANDLER_GO_ON;
36692 if (p->config_storage) {
36694 for (i = 0; i < srv->config_context->used; i++) {
36695 plugin_config *s = p->config_storage[i];
36698 array_free(s->request_header);
36699 array_free(s->response_header);
36700 array_free(s->environment);
36705 free(p->config_storage);
36712 return HANDLER_GO_ON;
36715 @@ -86,86 +86,83 @@
36716 SETDEFAULTS_FUNC(mod_setenv_set_defaults) {
36717 plugin_data *p = p_d;
36720 - config_values_t cv[] = {
36722 + config_values_t cv[] = {
36723 { "setenv.add-request-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
36724 { "setenv.add-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
36725 { "setenv.add-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
36726 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36730 if (!p) return HANDLER_ERROR;
36733 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36736 for (i = 0; i < srv->config_context->used; i++) {
36740 s = calloc(1, sizeof(plugin_config));
36741 s->request_header = array_init();
36742 s->response_header = array_init();
36743 s->environment = array_init();
36746 cv[0].destination = s->request_header;
36747 cv[1].destination = s->response_header;
36748 cv[2].destination = s->environment;
36751 p->config_storage[i] = s;
36754 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
36755 return HANDLER_ERROR;
36760 return HANDLER_GO_ON;
36763 -#define PATCH(x) \
36764 - p->conf.x = s->x;
36765 static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data *p) {
36767 plugin_config *s = p->config_storage[0];
36769 - PATCH(request_header);
36770 - PATCH(response_header);
36771 - PATCH(environment);
36774 + PATCH_OPTION(request_header);
36775 + PATCH_OPTION(response_header);
36776 + PATCH_OPTION(environment);
36778 /* skip the first, the global context */
36779 for (i = 1; i < srv->config_context->used; i++) {
36780 data_config *dc = (data_config *)srv->config_context->data[i];
36781 s = p->config_storage[i];
36784 /* condition didn't match */
36785 if (!config_check_cond(srv, con, dc)) continue;
36789 for (j = 0; j < dc->value->used; j++) {
36790 data_unset *du = dc->value->data[j];
36793 if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-request-header"))) {
36794 - PATCH(request_header);
36795 + PATCH_OPTION(request_header);
36796 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-response-header"))) {
36797 - PATCH(response_header);
36798 + PATCH_OPTION(response_header);
36799 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-environment"))) {
36800 - PATCH(environment);
36801 + PATCH_OPTION(environment);
36811 URIHANDLER_FUNC(mod_setenv_uri_handler) {
36812 plugin_data *p = p_d;
36817 if (con->plugin_ctx[p->id]) {
36818 hctx = con->plugin_ctx[p->id];
36820 hctx = handler_ctx_init();
36823 con->plugin_ctx[p->id] = hctx;
36826 @@ -180,52 +177,52 @@
36827 for (k = 0; k < p->conf.request_header->used; k++) {
36828 data_string *ds = (data_string *)p->conf.request_header->data[k];
36829 data_string *ds_dst;
36832 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
36833 ds_dst = data_string_init();
36837 buffer_copy_string_buffer(ds_dst->key, ds->key);
36838 buffer_copy_string_buffer(ds_dst->value, ds->value);
36841 array_insert_unique(con->request.headers, (data_unset *)ds_dst);
36845 for (k = 0; k < p->conf.environment->used; k++) {
36846 data_string *ds = (data_string *)p->conf.environment->data[k];
36847 data_string *ds_dst;
36850 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
36851 ds_dst = data_string_init();
36855 buffer_copy_string_buffer(ds_dst->key, ds->key);
36856 buffer_copy_string_buffer(ds_dst->value, ds->value);
36859 array_insert_unique(con->environment, (data_unset *)ds_dst);
36863 for (k = 0; k < p->conf.response_header->used; k++) {
36864 data_string *ds = (data_string *)p->conf.response_header->data[k];
36867 response_header_insert(srv, con, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
36872 return HANDLER_GO_ON;
36875 REQUESTDONE_FUNC(mod_setenv_reset) {
36876 plugin_data *p = p_d;
36882 if (con->plugin_ctx[p->id]) {
36883 handler_ctx_free(con->plugin_ctx[p->id]);
36884 con->plugin_ctx[p->id] = NULL;
36887 - return HANDLER_GO_ON;
36888 + return HANDLER_GO_ON;
36891 /* this function is called at dlopen() time and inits the callbacks */
36892 @@ -233,15 +230,15 @@
36893 int mod_setenv_plugin_init(plugin *p) {
36894 p->version = LIGHTTPD_VERSION_ID;
36895 p->name = buffer_init_string("setenv");
36898 p->init = mod_setenv_init;
36899 p->handle_uri_clean = mod_setenv_uri_handler;
36900 p->set_defaults = mod_setenv_set_defaults;
36901 p->cleanup = mod_setenv_free;
36904 p->handle_request_done = mod_setenv_reset;
36911 --- ../lighttpd-1.4.11/src/mod_simple_vhost.c 2005-11-18 15:16:13.000000000 +0200
36912 +++ lighttpd-1.4.12/src/mod_simple_vhost.c 2006-07-16 00:26:04.000000000 +0300
36915 #include "plugin.h"
36917 +#include "sys-files.h"
36919 #ifdef HAVE_CONFIG_H
36920 #include "config.h"
36923 buffer *server_root;
36924 buffer *default_host;
36925 buffer *document_root;
36928 buffer *docroot_cache_key;
36929 buffer *docroot_cache_value;
36930 buffer *docroot_cache_servername;
36931 @@ -28,138 +30,138 @@
36940 plugin_config **config_storage;
36941 - plugin_config conf;
36942 + plugin_config conf;
36945 INIT_FUNC(mod_simple_vhost_init) {
36949 p = calloc(1, sizeof(*p));
36952 p->doc_root = buffer_init();
36958 FREE_FUNC(mod_simple_vhost_free) {
36959 plugin_data *p = p_d;
36964 if (!p) return HANDLER_GO_ON;
36967 if (p->config_storage) {
36969 for (i = 0; i < srv->config_context->used; i++) {
36970 plugin_config *s = p->config_storage[i];
36973 buffer_free(s->document_root);
36974 buffer_free(s->default_host);
36975 buffer_free(s->server_root);
36978 buffer_free(s->docroot_cache_key);
36979 buffer_free(s->docroot_cache_value);
36980 buffer_free(s->docroot_cache_servername);
36987 free(p->config_storage);
36991 buffer_free(p->doc_root);
36997 return HANDLER_GO_ON;
37000 SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) {
37001 plugin_data *p = p_d;
37004 - config_values_t cv[] = {
37006 + config_values_t cv[] = {
37007 { "simple-vhost.server-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
37008 { "simple-vhost.default-host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
37009 { "simple-vhost.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
37010 { "simple-vhost.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
37011 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37015 if (!p) return HANDLER_ERROR;
37018 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37021 for (i = 0; i < srv->config_context->used; i++) {
37025 s = calloc(1, sizeof(plugin_config));
37028 s->server_root = buffer_init();
37029 s->default_host = buffer_init();
37030 s->document_root = buffer_init();
37033 s->docroot_cache_key = buffer_init();
37034 s->docroot_cache_value = buffer_init();
37035 s->docroot_cache_servername = buffer_init();
37040 cv[0].destination = s->server_root;
37041 cv[1].destination = s->default_host;
37042 cv[2].destination = s->document_root;
37043 cv[3].destination = &(s->debug);
37048 p->config_storage[i] = s;
37051 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37052 return HANDLER_ERROR;
37057 return HANDLER_GO_ON;
37060 static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) {
37061 stat_cache_entry *sce = NULL;
37064 buffer_prepare_copy(out, 128);
37066 if (p->conf.server_root->used) {
37067 buffer_copy_string_buffer(out, p->conf.server_root);
37071 /* a hostname has to start with a alpha-numerical character
37072 * and must not contain a slash "/"
37076 - BUFFER_APPEND_SLASH(out);
37079 + PATHNAME_APPEND_SLASH(out);
37081 if (NULL == (dp = strchr(host->ptr, ':'))) {
37082 buffer_append_string_buffer(out, host);
37084 buffer_append_string_len(out, host->ptr, dp - host->ptr);
37087 - BUFFER_APPEND_SLASH(out);
37089 + PATHNAME_APPEND_SLASH(out);
37091 if (p->conf.document_root->used > 2 && p->conf.document_root->ptr[0] == '/') {
37092 buffer_append_string_len(out, p->conf.document_root->ptr + 1, p->conf.document_root->used - 2);
37094 buffer_append_string_buffer(out, p->conf.document_root);
37095 - BUFFER_APPEND_SLASH(out);
37096 + PATHNAME_APPEND_SLASH(out);
37099 buffer_copy_string_buffer(out, con->conf.document_root);
37100 - BUFFER_APPEND_SLASH(out);
37101 + PATHNAME_APPEND_SLASH(out);
37105 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) {
37106 if (p->conf.debug) {
37107 log_error_write(srv, __FILE__, __LINE__, "sb",
37108 @@ -169,57 +171,53 @@
37109 } else if (!S_ISDIR(sce->st.st_mode)) {
37118 -#define PATCH(x) \
37119 - p->conf.x = s->x;
37120 static int mod_simple_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
37122 plugin_config *s = p->config_storage[0];
37124 - PATCH(server_root);
37125 - PATCH(default_host);
37126 - PATCH(document_root);
37128 - PATCH(docroot_cache_key);
37129 - PATCH(docroot_cache_value);
37130 - PATCH(docroot_cache_servername);
37134 + PATCH_OPTION(server_root);
37135 + PATCH_OPTION(default_host);
37136 + PATCH_OPTION(document_root);
37138 + PATCH_OPTION(docroot_cache_key);
37139 + PATCH_OPTION(docroot_cache_value);
37140 + PATCH_OPTION(docroot_cache_servername);
37142 + PATCH_OPTION(debug);
37144 /* skip the first, the global context */
37145 for (i = 1; i < srv->config_context->used; i++) {
37146 data_config *dc = (data_config *)srv->config_context->data[i];
37147 s = p->config_storage[i];
37150 /* condition didn't match */
37151 if (!config_check_cond(srv, con, dc)) continue;
37155 for (j = 0; j < dc->value->used; j++) {
37156 data_unset *du = dc->value->data[j];
37159 if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.server-root"))) {
37160 - PATCH(server_root);
37161 - PATCH(docroot_cache_key);
37162 - PATCH(docroot_cache_value);
37163 - PATCH(docroot_cache_servername);
37164 + PATCH_OPTION(server_root);
37165 + PATCH_OPTION(docroot_cache_key);
37166 + PATCH_OPTION(docroot_cache_value);
37167 + PATCH_OPTION(docroot_cache_servername);
37168 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.default-host"))) {
37169 - PATCH(default_host);
37170 + PATCH_OPTION(default_host);
37171 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.document-root"))) {
37172 - PATCH(document_root);
37173 + PATCH_OPTION(document_root);
37174 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.debug"))) {
37176 + PATCH_OPTION(debug);
37186 static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_data) {
37187 plugin_data *p = p_data;
37188 @@ -227,12 +225,12 @@
37190 * cache the last successfull translation from hostname (authority) to docroot
37191 * - this saves us a stat() call
37197 mod_simple_vhost_patch_connection(srv, con, p);
37199 - if (p->conf.docroot_cache_key->used &&
37201 + if (p->conf.docroot_cache_key->used &&
37202 con->uri.authority->used &&
37203 buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) {
37205 @@ -243,8 +241,8 @@
37206 if ((con->uri.authority->used == 0) ||
37207 build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) {
37208 /* not found, fallback the default-host */
37209 - if (build_doc_root(srv, con, p,
37211 + if (build_doc_root(srv, con, p,
37213 p->conf.default_host)) {
37214 return HANDLER_GO_ON;
37216 @@ -253,15 +251,15 @@
37218 buffer_copy_string_buffer(con->server_name, con->uri.authority);
37222 /* copy to cache */
37223 buffer_copy_string_buffer(p->conf.docroot_cache_key, con->uri.authority);
37224 buffer_copy_string_buffer(p->conf.docroot_cache_value, p->doc_root);
37225 buffer_copy_string_buffer(p->conf.docroot_cache_servername, con->server_name);
37228 buffer_copy_string_buffer(con->physical.doc_root, p->doc_root);
37232 return HANDLER_GO_ON;
37235 @@ -269,13 +267,13 @@
37236 int mod_simple_vhost_plugin_init(plugin *p) {
37237 p->version = LIGHTTPD_VERSION_ID;
37238 p->name = buffer_init_string("simple_vhost");
37241 p->init = mod_simple_vhost_init;
37242 p->set_defaults = mod_simple_vhost_set_defaults;
37243 p->handle_docroot = mod_simple_vhost_docroot;
37244 p->cleanup = mod_simple_vhost_free;
37252 --- ../lighttpd-1.4.11/src/mod_skeleton.c 2005-10-02 18:30:51.000000000 +0300
37253 +++ lighttpd-1.4.12/src/mod_skeleton.c 2006-07-16 00:26:03.000000000 +0300
37254 @@ -14,13 +14,13 @@
37257 * this is a skeleton for a lighttpd plugin
37260 * just replaces every occurance of 'skeleton' by your plugin name
37266 * :%s/skeleton/myhandler/
37272 @@ -33,12 +33,12 @@
37281 plugin_config **config_storage;
37283 - plugin_config conf;
37285 + plugin_config conf;
37289 @@ -47,36 +47,36 @@
37291 static handler_ctx * handler_ctx_init() {
37292 handler_ctx * hctx;
37295 hctx = calloc(1, sizeof(*hctx));
37301 static void handler_ctx_free(handler_ctx *hctx) {
37307 /* init the plugin data */
37308 INIT_FUNC(mod_skeleton_init) {
37312 p = calloc(1, sizeof(*p));
37315 p->match_buf = buffer_init();
37321 /* detroy the plugin data */
37322 FREE_FUNC(mod_skeleton_free) {
37323 plugin_data *p = p_d;
37328 if (!p) return HANDLER_GO_ON;
37331 if (p->config_storage) {
37334 @@ -84,18 +84,18 @@
37335 plugin_config *s = p->config_storage[i];
37340 array_free(s->match);
37345 free(p->config_storage);
37349 buffer_free(p->match_buf);
37355 return HANDLER_GO_ON;
37358 @@ -104,91 +104,88 @@
37359 SETDEFAULTS_FUNC(mod_skeleton_set_defaults) {
37360 plugin_data *p = p_d;
37363 - config_values_t cv[] = {
37365 + config_values_t cv[] = {
37366 { "skeleton.array", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
37367 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37371 if (!p) return HANDLER_ERROR;
37374 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37377 for (i = 0; i < srv->config_context->used; i++) {
37381 s = calloc(1, sizeof(plugin_config));
37382 s->match = array_init();
37385 cv[0].destination = s->match;
37388 p->config_storage[i] = s;
37391 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37392 return HANDLER_ERROR;
37397 return HANDLER_GO_ON;
37400 -#define PATCH(x) \
37401 - p->conf.x = s->x;
37402 static int mod_skeleton_patch_connection(server *srv, connection *con, plugin_data *p) {
37404 plugin_config *s = p->config_storage[0];
37409 + PATCH_OPTION(match);
37411 /* skip the first, the global context */
37412 for (i = 1; i < srv->config_context->used; i++) {
37413 data_config *dc = (data_config *)srv->config_context->data[i];
37414 s = p->config_storage[i];
37417 /* condition didn't match */
37418 if (!config_check_cond(srv, con, dc)) continue;
37422 for (j = 0; j < dc->value->used; j++) {
37423 data_unset *du = dc->value->data[j];
37426 if (buffer_is_equal_string(du->key, CONST_STR_LEN("skeleton.array"))) {
37428 + PATCH_OPTION(match);
37438 URIHANDLER_FUNC(mod_skeleton_uri_handler) {
37439 plugin_data *p = p_d;
37446 if (con->uri.path->used == 0) return HANDLER_GO_ON;
37449 mod_skeleton_patch_connection(srv, con, p);
37451 s_len = con->uri.path->used - 1;
37454 for (k = 0; k < p->conf.match->used; k++) {
37455 data_string *ds = (data_string *)p->conf.match->data[k];
37456 int ct_len = ds->value->used - 1;
37459 if (ct_len > s_len) continue;
37460 if (ds->value->used == 0) continue;
37463 if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
37464 con->http_status = 403;
37467 return HANDLER_FINISHED;
37473 return HANDLER_GO_ON;
37475 @@ -198,13 +195,13 @@
37476 int mod_skeleton_plugin_init(plugin *p) {
37477 p->version = LIGHTTPD_VERSION_ID;
37478 p->name = buffer_init_string("skeleton");
37481 p->init = mod_skeleton_init;
37482 p->handle_uri_clean = mod_skeleton_uri_handler;
37483 p->set_defaults = mod_skeleton_set_defaults;
37484 p->cleanup = mod_skeleton_free;
37492 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.c 1970-01-01 03:00:00.000000000 +0300
37493 +++ lighttpd-1.4.12/src/mod_sql_vhost_core.c 2006-07-16 00:26:04.000000000 +0300
37495 +#include <stdio.h>
37496 +#include <errno.h>
37497 +#include <fcntl.h>
37498 +#include <string.h>
37500 +#ifdef HAVE_CONFIG_H
37501 +#include "config.h"
37504 +#include "plugin.h"
37507 +#include "stat_cache.h"
37509 +#include "mod_sql_vhost_core.h"
37511 +#define plugin_data mod_sql_vhost_core_plugin_data
37512 +#define plugin_config mod_sql_vhost_core_plugin_config
37514 +/* init the plugin data */
37515 +INIT_FUNC(mod_sql_vhost_core_init) {
37518 + p = calloc(1, sizeof(*p));
37520 + p->docroot = buffer_init();
37521 + p->host = buffer_init();
37526 +/* cleanup the plugin data */
37527 +SERVER_FUNC(mod_sql_vhost_core_cleanup) {
37528 + plugin_data *p = p_d;
37532 + if (!p) return HANDLER_GO_ON;
37534 + if (p->config_storage) {
37536 + for (i = 0; i < srv->config_context->used; i++) {
37537 + plugin_config *s = p->config_storage[i];
37539 + if (!s) continue;
37541 + buffer_free(s->db);
37542 + buffer_free(s->user);
37543 + buffer_free(s->pass);
37544 + buffer_free(s->sock);
37545 + buffer_free(s->backend);
37549 + free(p->config_storage);
37551 + buffer_free(p->docroot);
37552 + buffer_free(p->host);
37556 + return HANDLER_GO_ON;
37559 +/* set configuration values */
37560 +SERVER_FUNC(mod_sql_vhost_core_set_defaults) {
37561 + plugin_data *p = p_d;
37565 + config_values_t cv[] = {
37566 + { "sql-vhost.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 0 * e.g. vhost */
37567 + { "sql-vhost.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 1 * lighty */
37568 + { "sql-vhost.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 2 * secrect */
37569 + { "sql-vhost.sock", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 3 * /tmp/mysql.sock */
37570 + { "sql-vhost.select-vhost", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 4 * SELECT ... FROM hosts WHERE hostname = ? */
37571 + { "sql-vhost.hostname", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 5 * 127.0.0.1 */
37572 + { "sql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 6 * 3306 */
37573 + { "sql-vhost.backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 7 * mysql */
37575 + /* backward compat */
37576 + { "mysql-vhost.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 8 == 0 */
37577 + { "mysql-vhost.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 9 == 1 */
37578 + { "mysql-vhost.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 10 == 2 */
37579 + { "mysql-vhost.sock", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 11 == 3 */
37580 + { "mysql-vhost.sql", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 12 == 4 */
37581 + { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER }, /* 13 == 5 */
37582 + { "mysql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 14 == 6 */
37584 + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37587 + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37589 + for (i = 0; i < srv->config_context->used; i++) {
37590 + plugin_config *s;
37592 + s = calloc(1, sizeof(plugin_config));
37593 + s->db = buffer_init();
37594 + s->user = buffer_init();
37595 + s->pass = buffer_init();
37596 + s->sock = buffer_init();
37597 + s->hostname = buffer_init();
37598 + s->backend = buffer_init();
37599 + s->port = 0; /* default port for mysql */
37600 + s->select_vhost = buffer_init();
37601 + s->backend_data = NULL;
37603 + cv[0].destination = s->db;
37604 + cv[1].destination = s->user;
37605 + cv[2].destination = s->pass;
37606 + cv[3].destination = s->sock;
37607 + cv[4].destination = s->select_vhost;
37608 + cv[5].destination = s->hostname;
37609 + cv[6].destination = &(s->port);
37610 + cv[7].destination = s->backend;
37612 + /* backend compat */
37613 + cv[8].destination = cv[0].destination;
37614 + cv[9].destination = cv[1].destination;
37615 + cv[10].destination = cv[2].destination;
37616 + cv[11].destination = cv[3].destination;
37617 + cv[12].destination = cv[4].destination;
37618 + cv[13].destination = cv[5].destination;
37619 + cv[14].destination = cv[6].destination;
37621 + p->config_storage[i] = s;
37623 + if (config_insert_values_global(srv,
37624 + ((data_config *)srv->config_context->data[i])->value,
37625 + cv)) return HANDLER_ERROR;
37627 + /* we only parse the config, the backend plugin will patch itself into the plugin-struct */
37630 + return HANDLER_GO_ON;
37633 +static int mod_sql_vhost_core_patch_connection(server *srv, connection *con, plugin_data *p) {
37635 + plugin_config *s = p->config_storage[0];
37637 + PATCH_OPTION(backend_data);
37638 + PATCH_OPTION(get_vhost);
37640 + /* skip the first, the global context */
37641 + for (i = 1; i < srv->config_context->used; i++) {
37642 + data_config *dc = (data_config *)srv->config_context->data[i];
37643 + s = p->config_storage[i];
37645 + /* condition didn't match */
37646 + if (!config_check_cond(srv, con, dc)) continue;
37648 + if (s->backend_data) {
37649 + PATCH_OPTION(backend_data);
37650 + PATCH_OPTION(get_vhost);
37657 +/* handle document root request */
37658 +CONNECTION_FUNC(mod_sql_vhost_core_handle_docroot) {
37659 + plugin_data *p = p_d;
37660 + stat_cache_entry *sce;
37662 + /* no host specified? */
37663 + if (!con->uri.authority->used) return HANDLER_GO_ON;
37665 + mod_sql_vhost_core_patch_connection(srv, con, p);
37667 + /* do we have backend ? */
37668 + if (!p->conf.get_vhost) return HANDLER_GO_ON;
37670 + /* ask the backend for the data */
37671 + if (0 != p->conf.get_vhost(srv, con, p->conf.backend_data, p->docroot, p->host)) {
37672 + return HANDLER_GO_ON;
37675 + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->docroot, &sce)) {
37676 + log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->docroot);
37677 + return HANDLER_GO_ON;
37679 + if (!S_ISDIR(sce->st.st_mode)) {
37680 + log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->docroot);
37681 + return HANDLER_GO_ON;
37684 + buffer_copy_string_buffer(con->server_name, p->host);
37685 + buffer_copy_string_buffer(con->physical.doc_root, p->docroot);
37687 + return HANDLER_GO_ON;
37690 +/* this function is called at dlopen() time and inits the callbacks */
37691 +int mod_sql_vhost_core_plugin_init(plugin *p) {
37692 + p->version = LIGHTTPD_VERSION_ID;
37693 + p->name = buffer_init_string("mod_sql_vhost_core");
37695 + p->init = mod_sql_vhost_core_init;
37696 + p->cleanup = mod_sql_vhost_core_cleanup;
37698 + p->set_defaults = mod_sql_vhost_core_set_defaults;
37699 + p->handle_docroot = mod_sql_vhost_core_handle_docroot;
37704 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.h 1970-01-01 03:00:00.000000000 +0300
37705 +++ lighttpd-1.4.12/src/mod_sql_vhost_core.h 2006-07-16 00:26:04.000000000 +0300
37707 +#ifndef _MOD_SQL_VHOST_CORE_H_
37708 +#define _MOD_SQL_VHOST_CORE_H_
37710 +#include "buffer.h"
37711 +#include "plugin.h"
37713 +#define SQLVHOST_BACKEND_GETVHOST_PARAMS \
37714 + (server *srv, connection *con, void *p_d, buffer *docroot, buffer *host)
37716 +#define SQLVHOST_BACKEND_GETVHOST_RETVAL handler_t
37718 +#define SQLVHOST_BACKEND_GETVHOST(name) \
37719 + SQLVHOST_BACKEND_GETVHOST_RETVAL name SQLVHOST_BACKEND_GETVHOST_PARAMS
37721 +#define SQLVHOST_BACKEND_GETVHOST_PTR(name) \
37722 + SQLVHOST_BACKEND_GETVHOST_RETVAL (* name)SQLVHOST_BACKEND_GETVHOST_PARAMS
37730 + buffer *hostname;
37731 + unsigned short port;
37734 + void *backend_data;
37736 + buffer *select_vhost;
37738 + SQLVHOST_BACKEND_GETVHOST_PTR(get_vhost);
37739 +} mod_sql_vhost_core_plugin_config;
37741 +/* global plugin data */
37748 + mod_sql_vhost_core_plugin_config **config_storage;
37750 + mod_sql_vhost_core_plugin_config conf;
37751 +} mod_sql_vhost_core_plugin_data;
37756 --- ../lighttpd-1.4.11/src/mod_ssi.c 2006-03-04 17:09:48.000000000 +0200
37757 +++ lighttpd-1.4.12/src/mod_ssi.c 2006-07-16 00:26:04.000000000 +0300
37759 #include <string.h>
37762 -#include <unistd.h>
37767 #include "inet_ntop_cache.h"
37769 #include "sys-socket.h"
37770 +#include "sys-strings.h"
37771 +#include "sys-files.h"
37775 @@ -39,15 +40,15 @@
37776 /* init the plugin data */
37777 INIT_FUNC(mod_ssi_init) {
37781 p = calloc(1, sizeof(*p));
37784 p->timefmt = buffer_init();
37785 p->stat_fn = buffer_init();
37788 p->ssi_vars = array_init();
37789 p->ssi_cgi_env = array_init();
37795 @@ -55,21 +56,21 @@
37796 FREE_FUNC(mod_ssi_free) {
37797 plugin_data *p = p_d;
37801 if (!p) return HANDLER_GO_ON;
37804 if (p->config_storage) {
37806 for (i = 0; i < srv->config_context->used; i++) {
37807 plugin_config *s = p->config_storage[i];
37810 array_free(s->ssi_extension);
37815 free(p->config_storage);
37819 array_free(p->ssi_vars);
37820 array_free(p->ssi_cgi_env);
37824 buffer_free(p->timefmt);
37825 buffer_free(p->stat_fn);
37831 return HANDLER_GO_ON;
37834 @@ -92,36 +93,36 @@
37835 const char *errptr;
37839 - config_values_t cv[] = {
37841 + config_values_t cv[] = {
37842 { "ssi.extension", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
37843 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37847 if (!p) return HANDLER_ERROR;
37850 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37853 for (i = 0; i < srv->config_context->used; i++) {
37857 s = calloc(1, sizeof(plugin_config));
37858 s->ssi_extension = array_init();
37861 cv[0].destination = s->ssi_extension;
37864 p->config_storage[i] = s;
37867 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37868 return HANDLER_ERROR;
37874 /* allow 2 params */
37875 if (NULL == (p->ssi_regex = pcre_compile("<!--#([a-z]+)\\s+(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?-->", 0, &errptr, &erroff, NULL))) {
37876 log_error_write(srv, __FILE__, __LINE__, "sds",
37880 return HANDLER_ERROR;
37882 @@ -130,52 +131,52 @@
37883 "mod_ssi: pcre support is missing, please recompile with pcre support or remove mod_ssi from the list of modules");
37884 return HANDLER_ERROR;
37888 return HANDLER_GO_ON;
37891 int ssi_env_add(array *env, const char *key, const char *val) {
37895 if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
37896 ds = data_string_init();
37898 buffer_copy_string(ds->key, key);
37899 buffer_copy_string(ds->value, val);
37902 array_insert_unique(env, (data_unset *)ds);
37910 * the next two functions are take from fcgi.c
37915 static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
37919 for (i = 0; i < con->request.headers->used; i++) {
37923 ds = (data_string *)con->request.headers->data[i];
37926 if (ds->value->used && ds->key->used) {
37928 buffer_reset(srv->tmp_buf);
37931 /* don't forward the Authorization: Header */
37932 if (0 == strcasecmp(ds->key->ptr, "AUTHORIZATION")) {
37937 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
37938 buffer_copy_string(srv->tmp_buf, "HTTP_");
37939 srv->tmp_buf->used--;
37943 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
37944 for (j = 0; j < ds->key->used - 1; j++) {
37946 @@ -189,33 +190,33 @@
37947 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
37949 srv->tmp_buf->ptr[srv->tmp_buf->used] = '\0';
37952 ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
37960 static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
37964 server_socket *srv_sock = con->srv_socket;
37968 char b2[INET6_ADDRSTRLEN + 1];
37971 #define CONST_STRING(x) \
37975 array_reset(p->ssi_cgi_env);
37978 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_SOFTWARE"), PACKAGE_NAME"/"PACKAGE_VERSION);
37979 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_NAME"),
37981 - inet_ntop(srv_sock->addr.plain.sa_family,
37982 - srv_sock->addr.plain.sa_family == AF_INET6 ?
37983 + inet_ntop(srv_sock->addr.plain.sa_family,
37984 + srv_sock->addr.plain.sa_family == AF_INET6 ?
37985 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
37986 (const void *) &(srv_sock->addr.ipv4.sin_addr),
37988 @@ -224,28 +225,28 @@
37991 ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1");
37997 ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
37999 ntohs(srv_sock->addr.ipv4.sin_port)
38004 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PORT"), buf);
38007 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_ADDR"),
38008 inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
38011 if (con->authed_user->used) {
38012 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_USER"),
38013 con->authed_user->ptr);
38017 if (con->request.content_length > 0) {
38018 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
38021 /* request.content_length < SSIZE_MAX, see request.c */
38022 ltostr(buf, con->request.content_length);
38023 ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf);
38024 @@ -271,30 +272,30 @@
38025 if (con->request.pathinfo->used) {
38026 ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), con->request.pathinfo->ptr);
38030 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_FILENAME"), con->physical.path->ptr);
38031 ssi_env_add(p->ssi_cgi_env, CONST_STRING("DOCUMENT_ROOT"), con->physical.doc_root->ptr);
38034 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_URI"), con->request.uri->ptr);
38035 ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), con->uri.query->used ? con->uri.query->ptr : "");
38036 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method));
38037 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200");
38038 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version));
38041 ssi_env_add_request_headers(srv, con, p);
38047 -static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
38048 +static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
38049 const char **l, size_t n) {
38050 size_t i, ssicmd = 0;
38058 - enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
38059 + enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
38060 SSI_CONFIG, SSI_PRINTENV, SSI_SET, SSI_IF, SSI_ELIF,
38061 SSI_ELSE, SSI_ENDIF, SSI_EXEC } type;
38063 @@ -310,27 +311,27 @@
38064 { "endif", SSI_ENDIF },
38065 { "else", SSI_ELSE },
38066 { "exec", SSI_EXEC },
38069 { NULL, SSI_UNSET }
38073 for (i = 0; ssicmds[i].var; i++) {
38074 if (0 == strcmp(l[1], ssicmds[i].var)) {
38075 ssicmd = ssicmds[i].type;
38084 int var = 0, enc = 0;
38085 const char *var_val = NULL;
38086 stat_cache_entry *sce = NULL;
38092 - enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
38093 + enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
38094 SSI_ECHO_LAST_MODIFIED, SSI_ECHO_USER_NAME } type;
38096 { "DATE_GMT", SSI_ECHO_DATE_GMT },
38097 @@ -339,27 +340,27 @@
38098 { "DOCUMENT_URI", SSI_ECHO_DOCUMENT_URI },
38099 { "LAST_MODIFIED", SSI_ECHO_LAST_MODIFIED },
38100 { "USER_NAME", SSI_ECHO_USER_NAME },
38103 { NULL, SSI_ECHO_UNSET }
38110 enum { SSI_ENC_UNSET, SSI_ENC_URL, SSI_ENC_NONE, SSI_ENC_ENTITY } type;
38112 { "url", SSI_ENC_URL },
38113 { "none", SSI_ENC_NONE },
38114 { "entity", SSI_ENC_ENTITY },
38117 { NULL, SSI_ENC_UNSET }
38121 for (i = 2; i < n; i += 2) {
38122 if (0 == strcmp(l[i], "var")) {
38129 for (j = 0; echovars[j].var; j++) {
38130 if (0 == strcmp(l[i+1], echovars[j].var)) {
38131 var = echovars[j].type;
38132 @@ -368,7 +369,7 @@
38134 } else if (0 == strcmp(l[i], "encoding")) {
38138 for (j = 0; encvars[j].var; j++) {
38139 if (0 == strcmp(l[i+1], encvars[j].var)) {
38140 enc = encvars[j].type;
38141 @@ -377,26 +378,26 @@
38144 log_error_write(srv, __FILE__, __LINE__, "sss",
38145 - "ssi: unknow attribute for ",
38146 + "ssi: unknow attribute for ",
38152 if (p->if_is_false) break;
38156 log_error_write(srv, __FILE__, __LINE__, "sss",
38159 l[1], "var is missing");
38163 stat_cache_get_entry(srv, con, con->physical.path, &sce);
38167 case SSI_ECHO_USER_NAME: {
38171 b = chunkqueue_get_append_buffer(con->write_queue);
38173 if (NULL == (pw = getpwuid(sce->st.st_uid))) {
38174 @@ -411,7 +412,7 @@
38176 case SSI_ECHO_LAST_MODIFIED: {
38177 time_t t = sce->st.st_mtime;
38180 b = chunkqueue_get_append_buffer(con->write_queue);
38181 if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
38182 buffer_copy_string(b, "(none)");
38183 @@ -422,7 +423,7 @@
38185 case SSI_ECHO_DATE_LOCAL: {
38186 time_t t = time(NULL);
38189 b = chunkqueue_get_append_buffer(con->write_queue);
38190 if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
38191 buffer_copy_string(b, "(none)");
38192 @@ -433,7 +434,7 @@
38194 case SSI_ECHO_DATE_GMT: {
38195 time_t t = time(NULL);
38198 b = chunkqueue_get_append_buffer(con->write_queue);
38199 if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
38200 buffer_copy_string(b, "(none)");
38201 @@ -444,7 +445,7 @@
38203 case SSI_ECHO_DOCUMENT_NAME: {
38207 b = chunkqueue_get_append_buffer(con->write_queue);
38208 if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
38209 buffer_copy_string_buffer(b, con->physical.path);
38210 @@ -461,15 +462,15 @@
38213 /* check if it is a cgi-var */
38216 b = chunkqueue_get_append_buffer(con->write_queue);
38219 if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) {
38220 buffer_copy_string_buffer(b, ds->value);
38222 buffer_copy_string(b, "(none)");
38229 @@ -481,7 +482,7 @@
38230 const char * file_path = NULL, *virt_path = NULL;
38235 for (i = 2; i < n; i += 2) {
38236 if (0 == strcmp(l[i], "file")) {
38237 file_path = l[i+1];
38238 @@ -489,28 +490,28 @@
38239 virt_path = l[i+1];
38241 log_error_write(srv, __FILE__, __LINE__, "sss",
38242 - "ssi: unknow attribute for ",
38243 + "ssi: unknow attribute for ",
38249 if (!file_path && !virt_path) {
38250 log_error_write(srv, __FILE__, __LINE__, "sss",
38253 l[1], "file or virtual are missing");
38258 if (file_path && virt_path) {
38259 log_error_write(srv, __FILE__, __LINE__, "sss",
38262 l[1], "only one of file and virtual is allowed here");
38269 if (p->if_is_false) break;
38273 /* current doc-root */
38274 if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
38275 @@ -519,46 +520,46 @@
38276 buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1);
38279 - buffer_copy_string(srv->tmp_buf, file_path);
38280 + buffer_copy_string(srv->tmp_buf, file_path);
38281 buffer_urldecode_path(srv->tmp_buf);
38282 - buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
38283 - buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
38284 + buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
38285 + buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
38290 if (virt_path[0] == '/') {
38291 buffer_copy_string(p->stat_fn, virt_path);
38293 /* there is always a / */
38294 sl = strrchr(con->uri.path->ptr, '/');
38297 buffer_copy_string_len(p->stat_fn, con->uri.path->ptr, sl - con->uri.path->ptr + 1);
38298 buffer_append_string(p->stat_fn, virt_path);
38302 buffer_urldecode_path(p->stat_fn);
38303 buffer_path_simplify(srv->tmp_buf, p->stat_fn);
38306 /* we have an uri */
38309 buffer_copy_string_buffer(p->stat_fn, con->physical.doc_root);
38310 buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
38314 if (0 == stat(p->stat_fn->ptr, &st)) {
38315 time_t t = st.st_mtime;
38320 b = chunkqueue_get_append_buffer(con->write_queue);
38323 const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };
38326 off_t s = st.st_size;
38329 for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);
38332 buffer_copy_off_t(b, s);
38333 buffer_append_string(b, abr[j]);
38335 @@ -579,7 +580,7 @@
38338 log_error_write(srv, __FILE__, __LINE__, "sbs",
38339 - "ssi: stating failed ",
38340 + "ssi: stating failed ",
38341 p->stat_fn, strerror(errno));
38344 @@ -593,33 +594,33 @@
38347 log_error_write(srv, __FILE__, __LINE__, "sss",
38348 - "ssi: unknow attribute for ",
38349 + "ssi: unknow attribute for ",
38355 if (p->if_is_false) break;
38362 if (NULL == (ds = (data_string *)array_get_unused_element(p->ssi_vars, TYPE_STRING))) {
38363 ds = data_string_init();
38365 buffer_copy_string(ds->key, key);
38366 buffer_copy_string(ds->value, val);
38369 array_insert_unique(p->ssi_vars, (data_unset *)ds);
38371 log_error_write(srv, __FILE__, __LINE__, "sss",
38372 - "ssi: var and value have to be set in",
38373 + "ssi: var and value have to be set in",
38380 if (p->if_is_false) break;
38383 for (i = 2; i < n; i += 2) {
38384 if (0 == strcmp(l[i], "timefmt")) {
38385 buffer_copy_string(p->timefmt, l[i+1]);
38386 @@ -632,63 +633,65 @@
38387 log_error_write(srv, __FILE__, __LINE__, "sssss",
38388 "ssi: unknow value for attribute '",
38395 log_error_write(srv, __FILE__, __LINE__, "sss",
38396 - "ssi: unknow attribute for ",
38397 + "ssi: unknow attribute for ",
38403 if (p->if_is_false) break;
38406 b = chunkqueue_get_append_buffer(con->write_queue);
38407 buffer_copy_string(b, "<pre>");
38408 for (i = 0; i < p->ssi_vars->used; i++) {
38409 data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]];
38412 buffer_append_string_buffer(b, ds->key);
38413 buffer_append_string(b, ": ");
38414 buffer_append_string_buffer(b, ds->value);
38415 buffer_append_string(b, "<br />");
38419 buffer_append_string(b, "</pre>");
38426 const char *cmd = NULL;
38428 int from_exec_fds[2];
38431 for (i = 2; i < n; i += 2) {
38432 if (0 == strcmp(l[i], "cmd")) {
38435 log_error_write(srv, __FILE__, __LINE__, "sss",
38436 - "ssi: unknow attribute for ",
38437 + "ssi: unknow attribute for ",
38443 if (p->if_is_false) break;
38446 /* create a return pipe and send output to the html-page
38448 - * as exec is assumed evil it is implemented synchronously
38450 + * as exec is assumed evil it is implemented synchronously
38457 if (pipe(from_exec_fds)) {
38458 - log_error_write(srv, __FILE__, __LINE__, "ss",
38459 + log_error_write(srv, __FILE__, __LINE__, "ss",
38460 "pipe failed: ", strerror(errno));
38466 switch (pid = fork()) {
38468 @@ -698,14 +701,14 @@
38469 close(from_exec_fds[1]);
38471 close(from_exec_fds[0]);
38475 close(STDIN_FILENO);
38478 execl("/bin/sh", "sh", "-c", cmd, NULL);
38481 log_error_write(srv, __FILE__, __LINE__, "sss", "spawing exec failed:", strerror(errno), cmd);
38487 @@ -718,9 +721,9 @@
38493 close(from_exec_fds[1]);
38496 /* wait for the client to end */
38497 if (-1 == waitpid(pid, &status, 0)) {
38498 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
38499 @@ -730,7 +733,7 @@
38502 if (ioctl(from_exec_fds[0], FIONREAD, &toread)) {
38503 - log_error_write(srv, __FILE__, __LINE__, "s",
38504 + log_error_write(srv, __FILE__, __LINE__, "s",
38505 "unexpected end-of-file (perhaps the ssi-exec process died)");
38508 @@ -738,10 +741,10 @@
38510 b = chunkqueue_get_append_buffer(con->write_queue);
38512 - buffer_prepare_copy(b, toread + 1);
38513 + buffer_prepare_copy(b, toread + 1);
38515 if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
38516 - /* read failed */
38517 + /* read failed */
38521 @@ -755,59 +758,58 @@
38522 log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally");
38524 close(from_exec_fds[0]);
38539 const char *expr = NULL;
38542 for (i = 2; i < n; i += 2) {
38543 if (0 == strcmp(l[i], "expr")) {
38546 log_error_write(srv, __FILE__, __LINE__, "sss",
38547 - "ssi: unknow attribute for ",
38548 + "ssi: unknow attribute for ",
38555 log_error_write(srv, __FILE__, __LINE__, "sss",
38558 l[1], "expr missing");
38563 if ((!p->if_is_false) &&
38564 - ((p->if_is_false_level == 0) ||
38565 + ((p->if_is_false_level == 0) ||
38566 (p->if_level < p->if_is_false_level))) {
38567 switch (ssi_eval_expr(srv, con, p, expr)) {
38570 - p->if_is_false = 1;
38572 + p->if_is_false = 1;
38573 p->if_is_false_level = p->if_level;
38576 - p->if_is_false = 0;
38578 + p->if_is_false = 0;
38593 if (p->if_is_false) {
38594 if ((p->if_level == p->if_is_false_level) &&
38595 (p->if_is_false_endif == 0)) {
38596 @@ -815,11 +817,11 @@
38599 p->if_is_false = 1;
38602 p->if_is_false_level = p->if_level;
38609 const char *expr = NULL;
38610 @@ -828,52 +830,52 @@
38613 log_error_write(srv, __FILE__, __LINE__, "sss",
38614 - "ssi: unknow attribute for ",
38615 + "ssi: unknow attribute for ",
38622 log_error_write(srv, __FILE__, __LINE__, "sss",
38625 l[1], "expr missing");
38633 if (p->if_level == p->if_is_false_level) {
38634 if ((p->if_is_false) &&
38635 (p->if_is_false_endif == 0)) {
38636 switch (ssi_eval_expr(srv, con, p, expr)) {
38639 - p->if_is_false = 1;
38641 + p->if_is_false = 1;
38642 p->if_is_false_level = p->if_level;
38645 - p->if_is_false = 0;
38647 + p->if_is_false = 0;
38651 - p->if_is_false = 1;
38652 + p->if_is_false = 1;
38653 p->if_is_false_level = p->if_level;
38654 p->if_is_false_endif = 1;
38668 if (p->if_level == p->if_is_false_level) {
38669 p->if_is_false = 0;
38670 p->if_is_false_endif = 0;
38676 log_error_write(srv, __FILE__, __LINE__, "ss",
38677 @@ -881,41 +883,41 @@
38688 static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) {
38699 /* get a stream to the file */
38702 array_reset(p->ssi_vars);
38703 array_reset(p->ssi_cgi_env);
38704 buffer_copy_string(p->timefmt, "%a, %d %b %Y %H:%M:%S %Z");
38706 build_ssi_cgi_vars(srv, con, p);
38707 p->if_is_false = 0;
38710 if (-1 == stream_open(&s, con->physical.path)) {
38711 log_error_write(srv, __FILE__, __LINE__, "sb",
38712 "stream-open: ", con->physical.path);
38720 - * <!--#element attribute=value attribute=value ... -->
38722 + * <!--#element attribute=value attribute=value ... -->
38725 - * errmsg -- missing
38726 + * errmsg -- missing
38730 @@ -937,13 +939,13 @@
38747 @@ -951,118 +953,115 @@
38759 - * The current date in Greenwich Mean Time.
38761 - * The current date in the local time zone.
38763 - * The filename (excluding directories) of the document requested by the user.
38765 - * 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.
38767 - * The last modification date of the document requested by the user.
38770 + * The current date in Greenwich Mean Time.
38772 + * The current date in the local time zone.
38774 + * The filename (excluding directories) of the document requested by the user.
38776 + * 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.
38778 + * The last modification date of the document requested by the user.
38780 * Contains the owner of the file which included it.
38784 -#ifdef HAVE_PCRE_H
38785 +#ifdef HAVE_PCRE_H
38786 for (i = 0; (n = pcre_exec(p->ssi_regex, NULL, s.start, s.size, i, 0, ovec, N * 3)) > 0; i = ovec[1]) {
38788 /* take everything from last offset to current match pos */
38791 if (!p->if_is_false) chunkqueue_append_file(con->write_queue, con->physical.path, i, ovec[0] - i);
38794 pcre_get_substring_list(s.start, ovec, n, &l);
38795 process_ssi_stmt(srv, con, p, l, n);
38796 pcre_free_substring_list(l);
38801 case PCRE_ERROR_NOMATCH:
38802 /* copy everything/the rest */
38803 chunkqueue_append_file(con->write_queue, con->physical.path, i, s.size - i);
38808 log_error_write(srv, __FILE__, __LINE__, "sd",
38809 "execution error while matching: ", n);
38821 con->file_started = 1;
38822 con->file_finished = 1;
38825 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
38828 /* reset physical.path */
38829 buffer_reset(con->physical.path);
38835 -#define PATCH(x) \
38836 - p->conf.x = s->x;
38837 static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p) {
38839 plugin_config *s = p->config_storage[0];
38841 - PATCH(ssi_extension);
38844 + PATCH_OPTION(ssi_extension);
38846 /* skip the first, the global context */
38847 for (i = 1; i < srv->config_context->used; i++) {
38848 data_config *dc = (data_config *)srv->config_context->data[i];
38849 s = p->config_storage[i];
38852 /* condition didn't match */
38853 if (!config_check_cond(srv, con, dc)) continue;
38857 for (j = 0; j < dc->value->used; j++) {
38858 data_unset *du = dc->value->data[j];
38861 if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.extension"))) {
38862 - PATCH(ssi_extension);
38863 + PATCH_OPTION(ssi_extension);
38873 URIHANDLER_FUNC(mod_ssi_physical_path) {
38874 plugin_data *p = p_d;
38878 if (con->physical.path->used == 0) return HANDLER_GO_ON;
38881 mod_ssi_patch_connection(srv, con, p);
38884 for (k = 0; k < p->conf.ssi_extension->used; k++) {
38885 data_string *ds = (data_string *)p->conf.ssi_extension->data[k];
38888 if (ds->value->used == 0) continue;
38891 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
38892 /* handle ssi-request */
38895 if (mod_ssi_handle_request(srv, con, p)) {
38897 con->http_status = 500;
38901 return HANDLER_FINISHED;
38907 return HANDLER_GO_ON;
38909 @@ -1072,13 +1071,13 @@
38910 int mod_ssi_plugin_init(plugin *p) {
38911 p->version = LIGHTTPD_VERSION_ID;
38912 p->name = buffer_init_string("ssi");
38915 p->init = mod_ssi_init;
38916 p->handle_subrequest_start = mod_ssi_physical_path;
38917 p->set_defaults = mod_ssi_set_defaults;
38918 p->cleanup = mod_ssi_free;
38926 --- ../lighttpd-1.4.11/src/mod_ssi.h 2005-08-11 01:26:39.000000000 +0300
38927 +++ lighttpd-1.4.12/src/mod_ssi.h 2006-07-16 00:26:04.000000000 +0300
38928 @@ -19,23 +19,23 @@
38933 -#ifdef HAVE_PCRE_H
38935 +#ifdef HAVE_PCRE_H
38947 array *ssi_cgi_env;
38950 int if_level, if_is_false_level, if_is_false, if_is_false_endif;
38953 plugin_config **config_storage;
38955 - plugin_config conf;
38957 + plugin_config conf;
38960 int ssi_eval_expr(server *srv, connection *con, plugin_data *p, const char *expr);
38961 --- ../lighttpd-1.4.11/src/mod_ssi_expr.c 2005-08-11 01:26:48.000000000 +0300
38962 +++ lighttpd-1.4.12/src/mod_ssi_expr.c 2006-07-16 00:26:04.000000000 +0300
38975 @@ -21,15 +21,15 @@
38977 ssi_val_t *ssi_val_init() {
38981 s = calloc(1, sizeof(*s));
38987 void ssi_val_free(ssi_val_t *s) {
38988 if (s->str) buffer_free(s->str);
38994 @@ -45,175 +45,175 @@
38995 ssi_tokenizer_t *t, int *token_id, buffer *token) {
39002 for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
39003 char c = t->input[t->offset];
39017 buffer_copy_string(token, "(=)");
39022 if (t->input[t->offset + 1] == '=') {
39030 buffer_copy_string(token, "(>=)");
39039 buffer_copy_string(token, "(>)");
39045 if (t->input[t->offset + 1] == '=') {
39053 buffer_copy_string(token, "(<=)");
39062 buffer_copy_string(token, "(<)");
39070 if (t->input[t->offset + 1] == '=') {
39078 buffer_copy_string(token, "(!=)");
39087 buffer_copy_string(token, "(!)");
39093 if (t->input[t->offset + 1] == '&') {
39101 buffer_copy_string(token, "(&&)");
39103 - log_error_write(srv, __FILE__, __LINE__, "sds",
39104 - "pos:", t->line_pos,
39105 + log_error_write(srv, __FILE__, __LINE__, "sds",
39106 + "pos:", t->line_pos,
39107 "missing second &");
39114 if (t->input[t->offset + 1] == '|') {
39122 buffer_copy_string(token, "(||)");
39124 - log_error_write(srv, __FILE__, __LINE__, "sds",
39125 - "pos:", t->line_pos,
39126 + log_error_write(srv, __FILE__, __LINE__, "sds",
39127 + "pos:", t->line_pos,
39128 "missing second |");
39142 /* search for the terminating " */
39143 for (i = 1; t->input[t->offset + i] && t->input[t->offset + i] != '\''; i++);
39146 if (t->input[t->offset + i]) {
39150 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
39153 t->offset += i + 1;
39154 t->line_pos += i + 1;
39158 - log_error_write(srv, __FILE__, __LINE__, "sds",
39159 - "pos:", t->line_pos,
39161 + log_error_write(srv, __FILE__, __LINE__, "sds",
39162 + "pos:", t->line_pos,
39163 "missing closing quote");
39179 buffer_copy_string(token, "(");
39189 buffer_copy_string(token, ")");
39192 if (t->input[t->offset + 1] == '{') {
39193 for (i = 2; t->input[t->offset + i] && t->input[t->offset + i] != '}'; i++);
39196 if (t->input[t->offset + i] != '}') {
39197 - log_error_write(srv, __FILE__, __LINE__, "sds",
39198 - "pos:", t->line_pos,
39199 + log_error_write(srv, __FILE__, __LINE__, "sds",
39200 + "pos:", t->line_pos,
39201 "missing closing quote");
39208 buffer_copy_string_len(token, t->input + t->offset + 2, i-3);
39210 for (i = 1; isalpha(t->input[t->offset + i]) || t->input[t->offset + i] == '_'; i++);
39213 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
39220 if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, token->ptr))) {
39221 buffer_copy_string_buffer(token, ds->value);
39222 } else if (NULL != (ds = (data_string *)array_get_element(p->ssi_vars, token->ptr))) {
39223 @@ -221,16 +221,16 @@
39225 buffer_copy_string(token, "");
39235 for (i = 0; isgraph(t->input[t->offset + i]); i++) {
39236 char d = t->input[t->offset + i];
39243 @@ -244,25 +244,25 @@
39252 buffer_copy_string_len(token, t->input + t->offset, i);
39269 } else if (t->offset < t->size) {
39270 - log_error_write(srv, __FILE__, __LINE__, "sds",
39271 - "pos:", t->line_pos,
39272 + log_error_write(srv, __FILE__, __LINE__, "sds",
39273 + "pos:", t->line_pos,
39277 @@ -275,50 +275,50 @@
39285 t.size = strlen(expr);
39298 /* default context */
39301 pParser = ssiexprparserAlloc( malloc );
39302 token = buffer_init();
39303 while((1 == (ret = ssi_expr_tokenizer(srv, con, p, &t, &token_id, token))) && context.ok) {
39304 ssiexprparser(pParser, token_id, token, &context);
39307 token = buffer_init();
39309 ssiexprparser(pParser, 0, token, &context);
39310 ssiexprparserFree(pParser, free );
39313 buffer_free(token);
39317 - log_error_write(srv, __FILE__, __LINE__, "s",
39318 + log_error_write(srv, __FILE__, __LINE__, "s",
39319 "expr parser failed");
39324 if (context.ok == 0) {
39325 - log_error_write(srv, __FILE__, __LINE__, "sds",
39326 - "pos:", t.line_pos,
39327 + log_error_write(srv, __FILE__, __LINE__, "sds",
39328 + "pos:", t.line_pos,
39329 "parser failed somehow near here");
39333 - log_error_write(srv, __FILE__, __LINE__, "ssd",
39334 + log_error_write(srv, __FILE__, __LINE__, "ssd",
39340 return context.val.bo;
39342 --- ../lighttpd-1.4.11/src/mod_ssi_expr.h 2005-08-11 01:26:48.000000000 +0300
39343 +++ lighttpd-1.4.12/src/mod_ssi_expr.h 2006-07-16 00:26:04.000000000 +0300
39347 enum { SSI_TYPE_UNSET, SSI_TYPE_BOOL, SSI_TYPE_STRING } type;
39364 --- ../lighttpd-1.4.11/src/mod_ssi_exprparser.c 2005-10-03 00:40:25.000000000 +0300
39365 +++ lighttpd-1.4.12/src/mod_ssi_exprparser.c 2006-07-17 22:02:23.000000000 +0300
39366 @@ -18,10 +18,10 @@
39367 /* Next is all token values, in a form suitable for use by makeheaders.
39368 ** This section will be null unless lemon is run with the -m switch.
39372 ** These constants (all generated automatically by the parser generator)
39373 ** specify the various kinds of tokens (terminals) that the parser
39377 ** Each symbol here is a terminal symbol in the grammar.
39380 ** and nonterminals. "int" is used otherwise.
39381 ** YYNOCODE is a number of type YYCODETYPE which corresponds
39382 ** to no legal terminal or nonterminal number. This
39383 -** number is used to fill in empty slots of the hash
39384 +** number is used to fill in empty slots of the hash
39386 ** YYFALLBACK If defined, this indicates that one or more tokens
39387 ** have fall-back values which should be used if the
39389 ** and nonterminal numbers. "unsigned char" is
39390 ** used if there are fewer than 250 rules and
39391 ** states combined. "int" is used otherwise.
39392 -** ssiexprparserTOKENTYPE is the data type used for minor tokens given
39393 +** ssiexprparserTOKENTYPE is the data type used for minor tokens given
39394 ** directly to the parser from the tokenizer.
39395 ** YYMINORTYPE is the data type used for all minor tokens.
39396 ** This is typically a union of many types, one of
39398 /* Next are that tables used to determine what action to take based on the
39399 ** current state and lookahead token. These tables are used to implement
39400 ** functions that take a state number and lookahead value and return an
39401 -** action integer.
39402 +** action integer.
39404 ** Suppose the action integer is N. Then the action is determined as
39406 @@ -116,7 +116,7 @@
39407 ** If the index value yy_shift_ofst[S]+X is out of range or if the value
39408 ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
39409 ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
39410 -** and that yy_default[S] should be used instead.
39411 +** and that yy_default[S] should be used instead.
39413 ** The formula above is for computing the action when the lookahead is
39414 ** a terminal symbol. If the lookahead is a non-terminal (as occurs after
39415 @@ -168,7 +168,7 @@
39417 /* The next table maps tokens into fallback tokens. If a construct
39418 ** like the following:
39421 ** %fallback ID X Y Z.
39423 ** appears in the grammer, then ID becomes a fallback token for X, Y,
39424 @@ -219,10 +219,10 @@
39425 #endif /* NDEBUG */
39430 ** Turn parser tracing on by giving a stream to which to write the trace
39431 ** and a prompt to preface each trace message. Tracing is turned off
39432 -** by making either argument NULL
39433 +** by making either argument NULL
39437 @@ -247,7 +247,7 @@
39439 /* For tracing shifts, the names of all terminals and nonterminals
39440 ** are required. The following table supplies these names */
39441 -static const char *yyTokenName[] = {
39442 +static const char *yyTokenName[] = {
39443 "$", "AND", "OR", "EQ",
39444 "NE", "GT", "GE", "LT",
39445 "LE", "NOT", "LPARAN", "RPARAN",
39446 @@ -295,7 +295,7 @@
39452 ** This function allocates a new parser.
39453 ** The only argument is a pointer to a function which works like
39455 @@ -326,7 +326,7 @@
39456 /* Here is inserted the actions which take place when a
39457 ** terminal or non-terminal is destroyed. This can happen
39458 ** when the symbol is popped from the stack during a
39459 - ** reduce or during error processing or when a parser is
39460 + ** reduce or during error processing or when a parser is
39461 ** being destroyed before it is finished parsing.
39463 ** Note: during a reduce, the only symbols destroyed are those
39464 @@ -379,7 +379,7 @@
39470 ** Deallocate and destroy a parser. Destructors are all called for
39471 ** all stack elements before shutting the parser down.
39473 @@ -415,7 +415,7 @@
39476 int stateno = pParser->yystack[pParser->yyidx].stateno;
39479 /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
39480 i = yy_shift_ofst[stateno];
39481 if( i==YY_SHIFT_USE_DFLT ){
39482 @@ -459,7 +459,7 @@
39485 int stateno = pParser->yystack[pParser->yyidx].stateno;
39488 i = yy_reduce_ofst[stateno];
39489 if( i==YY_REDUCE_USE_DFLT ){
39490 return yy_default[stateno];
39491 @@ -559,7 +559,7 @@
39492 ssiexprparserARG_FETCH;
39493 yymsp = &yypParser->yystack[yypParser->yyidx];
39495 - if( yyTraceFILE && yyruleno>=0
39496 + if( yyTraceFILE && yyruleno>=0
39497 && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
39498 fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
39499 yyRuleName[yyruleno]);
39500 @@ -872,7 +872,7 @@
39501 #ifdef YYERRORSYMBOL
39502 /* A syntax error has occurred.
39503 ** The response to an error depends upon whether or not the
39504 - ** grammar defines an error token "ERROR".
39505 + ** grammar defines an error token "ERROR".
39507 ** This is what we do if the grammar does define ERROR:
39509 --- ../lighttpd-1.4.11/src/mod_staticfile.c 2006-02-15 14:31:14.000000000 +0200
39510 +++ lighttpd-1.4.12/src/mod_staticfile.c 2006-07-16 00:26:03.000000000 +0300
39512 #include "http_chunk.h"
39513 #include "response.h"
39515 +#include "sys-files.h"
39516 +#include "sys-strings.h"
39518 * this is a staticfile for a lighttpd plugin
39524 @@ -29,48 +31,48 @@
39533 plugin_config **config_storage;
39535 - plugin_config conf;
39537 + plugin_config conf;
39540 /* init the plugin data */
39541 INIT_FUNC(mod_staticfile_init) {
39545 p = calloc(1, sizeof(*p));
39548 p->range_buf = buffer_init();
39554 -/* detroy the plugin data */
39555 +/* destroy the plugin data */
39556 FREE_FUNC(mod_staticfile_free) {
39557 plugin_data *p = p_d;
39562 if (!p) return HANDLER_GO_ON;
39565 if (p->config_storage) {
39567 for (i = 0; i < srv->config_context->used; i++) {
39568 plugin_config *s = p->config_storage[i];
39571 array_free(s->exclude_ext);
39576 free(p->config_storage);
39578 buffer_free(p->range_buf);
39584 return HANDLER_GO_ON;
39587 @@ -79,63 +81,60 @@
39588 SETDEFAULTS_FUNC(mod_staticfile_set_defaults) {
39589 plugin_data *p = p_d;
39592 - config_values_t cv[] = {
39594 + config_values_t cv[] = {
39595 { "static-file.exclude-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
39596 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
39600 if (!p) return HANDLER_ERROR;
39603 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
39606 for (i = 0; i < srv->config_context->used; i++) {
39610 s = calloc(1, sizeof(plugin_config));
39611 s->exclude_ext = array_init();
39614 cv[0].destination = s->exclude_ext;
39617 p->config_storage[i] = s;
39620 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
39621 return HANDLER_ERROR;
39626 return HANDLER_GO_ON;
39629 -#define PATCH(x) \
39630 - p->conf.x = s->x;
39631 static int mod_staticfile_patch_connection(server *srv, connection *con, plugin_data *p) {
39633 plugin_config *s = p->config_storage[0];
39635 - PATCH(exclude_ext);
39638 + PATCH_OPTION(exclude_ext);
39640 /* skip the first, the global context */
39641 for (i = 1; i < srv->config_context->used; i++) {
39642 data_config *dc = (data_config *)srv->config_context->data[i];
39643 s = p->config_storage[i];
39646 /* condition didn't match */
39647 if (!config_check_cond(srv, con, dc)) continue;
39651 for (j = 0; j < dc->value->used; j++) {
39652 data_unset *du = dc->value->data[j];
39655 if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.exclude-extensions"))) {
39656 - PATCH(exclude_ext);
39657 + PATCH_OPTION(exclude_ext);
39667 static int http_response_parse_range(server *srv, connection *con, plugin_data *p) {
39669 @@ -146,69 +145,69 @@
39671 stat_cache_entry *sce = NULL;
39672 buffer *content_type = NULL;
39675 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
39681 end = sce->st.st_size - 1;
39684 con->response.content_length = 0;
39687 if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {
39688 content_type = ds->value;
39692 for (s = con->request.http_range, error = 0;
39693 !error && *s && NULL != (minus = strchr(s, '-')); ) {
39702 le = strtoll(s, &err, 10);
39706 /* RFC 2616 - 14.35.1 */
39709 con->http_status = 416;
39711 } else if (*err == '\0') {
39716 end = sce->st.st_size - 1;
39717 start = sce->st.st_size + le;
39718 } else if (*err == ',') {
39723 end = sce->st.st_size - 1;
39724 start = sce->st.st_size + le;
39730 } else if (*(minus+1) == '\0' || *(minus+1) == ',') {
39734 la = strtoll(s, &err, 10);
39737 if (err == minus) {
39741 if (*(err + 1) == '\0') {
39745 end = sce->st.st_size - 1;
39749 } else if (*(err + 1) == ',') {
39754 end = sce->st.st_size - 1;
39757 @@ -220,64 +219,64 @@
39760 /* <start>-<stop> */
39763 la = strtoll(s, &err, 10);
39766 if (err == minus) {
39767 le = strtoll(minus+1, &err, 10);
39770 /* RFC 2616 - 14.35.1 */
39776 if (*err == '\0') {
39783 } else if (*err == ',') {
39806 if (start < 0) start = 0;
39809 /* RFC 2616 - 14.35.1 */
39810 if (end > sce->st.st_size - 1) end = sce->st.st_size - 1;
39813 if (start > sce->st.st_size - 1) {
39817 con->http_status = 416;
39824 /* write boundary-header */
39828 b = chunkqueue_get_append_buffer(con->write_queue);
39831 buffer_copy_string(b, "\r\n--");
39832 buffer_append_string(b, boundary);
39835 /* write Content-Range */
39836 buffer_append_string(b, "\r\nContent-Range: bytes ");
39837 buffer_append_off_t(b, start);
39838 @@ -285,54 +284,54 @@
39839 buffer_append_off_t(b, end);
39840 buffer_append_string(b, "/");
39841 buffer_append_off_t(b, sce->st.st_size);
39844 buffer_append_string(b, "\r\nContent-Type: ");
39845 buffer_append_string_buffer(b, content_type);
39848 /* write END-OF-HEADER */
39849 buffer_append_string(b, "\r\n\r\n");
39852 con->response.content_length += b->used - 1;
39858 chunkqueue_append_file(con->write_queue, con->physical.path, start, end - start + 1);
39859 con->response.content_length += end - start + 1;
39864 /* something went wrong */
39865 if (error) return -1;
39869 /* add boundary end */
39873 b = chunkqueue_get_append_buffer(con->write_queue);
39876 buffer_copy_string_len(b, "\r\n--", 4);
39877 buffer_append_string(b, boundary);
39878 buffer_append_string_len(b, "--\r\n", 4);
39881 con->response.content_length += b->used - 1;
39884 /* set header-fields */
39887 buffer_copy_string(p->range_buf, "multipart/byteranges; boundary=");
39888 buffer_append_string(p->range_buf, boundary);
39891 /* overwrite content-type */
39892 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->range_buf));
39894 /* add Content-Range-header */
39897 buffer_copy_string(p->range_buf, "bytes ");
39898 buffer_append_off_t(p->range_buf, start);
39899 buffer_append_string(p->range_buf, "-");
39900 buffer_append_off_t(p->range_buf, end);
39901 buffer_append_string(p->range_buf, "/");
39902 buffer_append_off_t(p->range_buf, sce->st.st_size);
39905 response_header_insert(srv, con, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(p->range_buf));
39908 @@ -347,12 +346,12 @@
39909 stat_cache_entry *sce = NULL;
39914 /* someone else has done a decision for us */
39915 if (con->http_status != 0) return HANDLER_GO_ON;
39916 if (con->uri.path->used == 0) return HANDLER_GO_ON;
39917 if (con->physical.path->used == 0) return HANDLER_GO_ON;
39920 /* someone else has handled this request */
39921 if (con->mode != DIRECT) return HANDLER_GO_ON;
39923 @@ -365,52 +364,52 @@
39925 return HANDLER_GO_ON;
39929 mod_staticfile_patch_connection(srv, con, p);
39932 s_len = con->uri.path->used - 1;
39935 /* ignore certain extensions */
39936 for (k = 0; k < p->conf.exclude_ext->used; k++) {
39937 - ds = (data_string *)p->conf.exclude_ext->data[k];
39939 + ds = (data_string *)p->conf.exclude_ext->data[k];
39941 if (ds->value->used == 0) continue;
39943 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
39944 return HANDLER_GO_ON;
39950 if (con->conf.log_request_handling) {
39951 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling file as static file");
39955 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
39956 con->http_status = 403;
39959 log_error_write(srv, __FILE__, __LINE__, "sbsb",
39960 "not a regular file:", con->uri.path,
39961 "->", con->physical.path);
39964 return HANDLER_FINISHED;
39967 - /* we only handline regular files */
39969 + /* we only handle regular files */
39970 if (!S_ISREG(sce->st.st_mode)) {
39971 con->http_status = 404;
39974 if (con->conf.log_file_not_found) {
39975 log_error_write(srv, __FILE__, __LINE__, "sbsb",
39976 "not a regular file:", con->uri.path,
39981 return HANDLER_FINISHED;
39984 - /* mod_compress might set several data directly, don't overwrite them */
39986 + /* mod_compress might set several parameters directly; don't overwrite them */
39988 /* set response content-type, if not set already */
39990 if (NULL == array_get_element(con->response.headers, "Content-Type")) {
39991 @@ -420,15 +419,15 @@
39992 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
39997 if (NULL == array_get_element(con->response.headers, "ETag")) {
39998 /* generate e-tag */
39999 etag_mutate(con->physical.etag, sce->etag);
40002 response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
40004 response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes"));
40007 /* prepare header */
40008 if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
40009 mtime = strftime_cache_get(srv, sce->st.st_mtime);
40010 @@ -444,34 +443,34 @@
40011 /* check if we have a conditional GET */
40013 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If-Range"))) {
40014 - /* if the value is the same as our ETag, we do a Range-request,
40015 + /* if the value is the same as our ETag, we do a Range-request,
40016 * otherwise a full 200 */
40018 if (!buffer_is_equal(ds->value, con->physical.etag)) {
40019 do_range_request = 0;
40024 if (do_range_request) {
40025 /* content prepared, I'm done */
40026 con->file_finished = 1;
40029 if (0 == http_response_parse_range(srv, con, p)) {
40030 con->http_status = 206;
40032 return HANDLER_FINISHED;
40037 /* if we are still here, prepare body */
40039 - /* we add it here for all requests
40040 - * the HEAD request will drop it afterwards again
40042 + /* we add it here for all requests
40043 + * the HEAD request will drop it afterwards again
40045 http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
40048 con->file_finished = 1;
40051 return HANDLER_FINISHED;
40054 @@ -480,13 +479,13 @@
40055 int mod_staticfile_plugin_init(plugin *p) {
40056 p->version = LIGHTTPD_VERSION_ID;
40057 p->name = buffer_init_string("staticfile");
40060 p->init = mod_staticfile_init;
40061 p->handle_subrequest_start = mod_staticfile_subrequest;
40062 p->set_defaults = mod_staticfile_set_defaults;
40063 p->cleanup = mod_staticfile_free;
40071 --- ../lighttpd-1.4.11/src/mod_status.c 2006-01-10 21:45:32.000000000 +0200
40072 +++ lighttpd-1.4.12/src/mod_status.c 2006-07-16 00:26:04.000000000 +0300
40075 #include <stdlib.h>
40076 #include <string.h>
40077 -#include <unistd.h>
40081 @@ -29,114 +28,114 @@
40087 double traffic_out;
40091 double mod_5s_traffic_out[5];
40092 double mod_5s_requests[5];
40096 double rel_traffic_out;
40097 double rel_requests;
40100 double abs_traffic_out;
40101 double abs_requests;
40104 double bytes_written;
40107 buffer *module_list;
40110 plugin_config **config_storage;
40112 - plugin_config conf;
40114 + plugin_config conf;
40117 INIT_FUNC(mod_status_init) {
40122 p = calloc(1, sizeof(*p));
40125 p->traffic_out = p->requests = 0;
40126 p->rel_traffic_out = p->rel_requests = 0;
40127 p->abs_traffic_out = p->abs_requests = 0;
40128 p->bytes_written = 0;
40129 p->module_list = buffer_init();
40132 for (i = 0; i < 5; i++) {
40133 p->mod_5s_traffic_out[i] = p->mod_5s_requests[i] = 0;
40140 FREE_FUNC(mod_status_free) {
40141 plugin_data *p = p_d;
40146 if (!p) return HANDLER_GO_ON;
40149 buffer_free(p->module_list);
40152 if (p->config_storage) {
40154 for (i = 0; i < srv->config_context->used; i++) {
40155 plugin_config *s = p->config_storage[i];
40158 buffer_free(s->status_url);
40159 buffer_free(s->statistics_url);
40160 buffer_free(s->config_url);
40165 free(p->config_storage);
40174 return HANDLER_GO_ON;
40177 SETDEFAULTS_FUNC(mod_status_set_defaults) {
40178 plugin_data *p = p_d;
40181 - config_values_t cv[] = {
40183 + config_values_t cv[] = {
40184 { "status.status-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
40185 { "status.config-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
40186 { "status.enable-sort", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
40187 { "status.statistics-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
40188 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
40192 if (!p) return HANDLER_ERROR;
40195 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
40198 for (i = 0; i < srv->config_context->used; i++) {
40202 s = calloc(1, sizeof(plugin_config));
40203 s->config_url = buffer_init();
40204 s->status_url = buffer_init();
40206 s->statistics_url = buffer_init();
40209 cv[0].destination = s->status_url;
40210 cv[1].destination = s->config_url;
40211 cv[2].destination = &(s->sort);
40212 cv[3].destination = s->statistics_url;
40215 p->config_storage[i] = s;
40218 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
40219 return HANDLER_ERROR;
40224 return HANDLER_GO_ON;
40227 @@ -151,7 +150,7 @@
40228 buffer_append_string(b, value);
40229 BUFFER_APPEND_STRING_CONST(b, "</td>\n");
40230 BUFFER_APPEND_STRING_CONST(b, " </tr>\n");
40236 @@ -161,13 +160,13 @@
40237 buffer_append_string(b, key);
40238 BUFFER_APPEND_STRING_CONST(b, "</th>\n");
40239 BUFFER_APPEND_STRING_CONST(b, " </tr>\n");
40245 static int mod_status_header_append_sort(buffer *b, void *p_d, const char* key) {
40246 plugin_data *p = p_d;
40249 if (p->conf.sort) {
40250 BUFFER_APPEND_STRING_CONST(b, "<th class=\"status\"><a href=\"#\" class=\"sortheader\" onclick=\"resort(this);return false;\">");
40251 buffer_append_string(b, key);
40252 @@ -177,13 +176,13 @@
40253 buffer_append_string(b, key);
40254 BUFFER_APPEND_STRING_CONST(b, "</th>\n");
40261 static int mod_status_get_multiplier(double *avg, char *multiplier, int size) {
40265 if (*avg > size) { *avg /= size; *multiplier = 'k'; }
40266 if (*avg > size) { *avg /= size; *multiplier = 'M'; }
40267 if (*avg > size) { *avg /= size; *multiplier = 'G'; }
40268 @@ -202,21 +201,21 @@
40271 char multiplier = '\0';
40277 int days, hours, mins, seconds;
40280 b = chunkqueue_get_append_buffer(con->write_queue);
40282 - BUFFER_COPY_STRING_CONST(b,
40283 + BUFFER_COPY_STRING_CONST(b,
40284 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
40285 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
40286 " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
40287 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
40289 " <title>Status</title>\n");
40292 BUFFER_APPEND_STRING_CONST(b,
40293 " <style type=\"text/css\">\n"
40294 " table.status { border: black solid thin; }\n"
40295 @@ -226,14 +225,14 @@
40296 " a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n"
40297 " span.sortarrow { color: white; text-decoration: none; }\n"
40301 if (p->conf.sort) {
40302 BUFFER_APPEND_STRING_CONST(b,
40303 "<script type=\"text/javascript\">\n"
40305 "var sort_column;\n"
40306 "var prev_span = null;\n");
40309 BUFFER_APPEND_STRING_CONST(b,
40310 "function get_inner_text(el) {\n"
40311 " if((typeof el == 'string')||(typeof el == 'undefined'))\n"
40312 @@ -251,7 +250,7 @@
40318 BUFFER_APPEND_STRING_CONST(b,
40319 "function sortfn(a,b) {\n"
40320 " var at = get_inner_text(a.cells[sort_column]);\n"
40321 @@ -266,7 +265,7 @@
40322 " else return 1;\n"
40327 BUFFER_APPEND_STRING_CONST(b,
40328 "function resort(lnk) {\n"
40329 " var span = lnk.childNodes[1];\n"
40330 @@ -276,7 +275,7 @@
40331 " rows[j-1] = table.rows[j];\n"
40332 " sort_column = lnk.parentNode.cellIndex;\n"
40333 " rows.sort(sortfn);\n");
40336 BUFFER_APPEND_STRING_CONST(b,
40337 " if (prev_span != null) prev_span.innerHTML = '';\n"
40338 " if (span.getAttribute('sortdir')=='down') {\n"
40339 @@ -294,175 +293,175 @@
40344 - BUFFER_APPEND_STRING_CONST(b,
40346 + BUFFER_APPEND_STRING_CONST(b,
40355 /* connection listing */
40356 BUFFER_APPEND_STRING_CONST(b, "<h1>Server-Status</h1>");
40358 - BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">");
40359 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\">");
40361 + BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" id=\"status\" summary=\"Server Status\">");
40362 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\"><span id=\"host_addr\">");
40363 buffer_append_string_buffer(b, con->uri.authority);
40364 - BUFFER_APPEND_STRING_CONST(b, " (");
40365 + BUFFER_APPEND_STRING_CONST(b, "</span> (<span id=\"host_name\">");
40366 buffer_append_string_buffer(b, con->server_name);
40367 - BUFFER_APPEND_STRING_CONST(b, ")</td></tr>\n");
40368 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\">");
40370 + BUFFER_APPEND_STRING_CONST(b, "</span>)</td></tr>\n");
40371 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\" id=\"uptime\">");
40373 ts = srv->cur_ts - srv->startup_ts;
40376 days = ts / (60 * 60 * 24);
40377 ts %= (60 * 60 * 24);
40380 hours = ts / (60 * 60);
40392 buffer_append_long(b, days);
40393 BUFFER_APPEND_STRING_CONST(b, " days ");
40398 buffer_append_long(b, hours);
40399 BUFFER_APPEND_STRING_CONST(b, " hours ");
40404 buffer_append_long(b, mins);
40405 BUFFER_APPEND_STRING_CONST(b, " min ");
40409 buffer_append_long(b, seconds);
40410 BUFFER_APPEND_STRING_CONST(b, " s");
40413 BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40414 BUFFER_APPEND_STRING_CONST(b, "<tr><td>Started at</td><td class=\"string\">");
40417 ts = srv->startup_ts;
40419 - strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts));
40421 + strftime(buf, sizeof(buf) - 1, "<span id=\"start_date\">%Y-%m-%d</span> <span id=\"start_time\">%H:%M:%S</span>", localtime(&ts));
40422 buffer_append_string(b, buf);
40423 BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40428 BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">absolute (since start)</th></tr>\n");
40430 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40432 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\" ><span id=\"requests\">");
40433 avg = p->abs_requests;
40435 mod_status_get_multiplier(&avg, &multiplier, 1000);
40438 buffer_append_long(b, avg);
40439 - BUFFER_APPEND_STRING_CONST(b, " ");
40440 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_mult\">");
40441 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40442 - BUFFER_APPEND_STRING_CONST(b, "req</td></tr>\n");
40444 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40445 + BUFFER_APPEND_STRING_CONST(b, "</span>req</td></tr>\n");
40447 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic\">");
40448 avg = p->abs_traffic_out;
40450 mod_status_get_multiplier(&avg, &multiplier, 1024);
40452 sprintf(buf, "%.2f", avg);
40453 buffer_append_string(b, buf);
40454 - BUFFER_APPEND_STRING_CONST(b, " ");
40455 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"traffic_mult\">");
40456 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40457 - BUFFER_APPEND_STRING_CONST(b, "byte</td></tr>\n");
40458 + BUFFER_APPEND_STRING_CONST(b, "</span>byte</td></tr>\n");
40462 BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (since start)</th></tr>\n");
40464 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40466 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_avg\">");
40467 avg = p->abs_requests / (srv->cur_ts - srv->startup_ts);
40469 mod_status_get_multiplier(&avg, &multiplier, 1000);
40471 buffer_append_long(b, avg);
40472 - BUFFER_APPEND_STRING_CONST(b, " ");
40473 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_avg_mult\">");
40474 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40475 - BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
40477 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40478 + BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
40480 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic_avg\">");
40481 avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts);
40483 mod_status_get_multiplier(&avg, &multiplier, 1024);
40485 sprintf(buf, "%.2f", avg);
40486 buffer_append_string(b, buf);
40487 - BUFFER_APPEND_STRING_CONST(b, " ");
40488 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"traffic_avg_mult\">");
40489 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40490 - BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
40491 + BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
40497 BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n");
40498 for (j = 0, avg = 0; j < 5; j++) {
40499 avg += p->mod_5s_requests[j];
40505 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40507 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_sliding_avg\">");
40509 mod_status_get_multiplier(&avg, &multiplier, 1000);
40511 buffer_append_long(b, avg);
40512 - BUFFER_APPEND_STRING_CONST(b, " ");
40513 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_avg_mult\">");
40514 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40516 - BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
40519 + BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
40521 for (j = 0, avg = 0; j < 5; j++) {
40522 avg += p->mod_5s_traffic_out[j];
40528 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40530 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"requests_sliding_traffic\">");
40532 mod_status_get_multiplier(&avg, &multiplier, 1024);
40534 sprintf(buf, "%.2f", avg);
40535 buffer_append_string(b, buf);
40536 - BUFFER_APPEND_STRING_CONST(b, " ");
40537 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_traffic_mult\">");
40538 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40539 - BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
40541 + BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
40543 BUFFER_APPEND_STRING_CONST(b, "</table>\n");
40548 BUFFER_APPEND_STRING_CONST(b, "<hr />\n<pre><b>legend</b>\n");
40549 BUFFER_APPEND_STRING_CONST(b, ". = connect, C = close, E = hard error\n");
40550 BUFFER_APPEND_STRING_CONST(b, "r = read, R = read-POST, W = write, h = handle-request\n");
40551 BUFFER_APPEND_STRING_CONST(b, "q = request-start, Q = request-end\n");
40552 BUFFER_APPEND_STRING_CONST(b, "s = response-start, S = response-end\n");
40554 - BUFFER_APPEND_STRING_CONST(b, "<b>");
40556 + BUFFER_APPEND_STRING_CONST(b, "<strong><span id=\"connections\">");
40557 buffer_append_long(b, srv->conns->used);
40558 - BUFFER_APPEND_STRING_CONST(b, " connections</b>\n");
40560 + BUFFER_APPEND_STRING_CONST(b, "</span> connections</strong>\n");
40562 for (j = 0; j < srv->conns->used; j++) {
40563 connection *c = srv->conns->ptr[j];
40564 const char *state = connection_get_short_state(c->state);
40567 buffer_append_string_len(b, state, 1);
40570 if (((j + 1) % 50) == 0) {
40571 BUFFER_APPEND_STRING_CONST(b, "\n");
40576 BUFFER_APPEND_STRING_CONST(b, "\n</pre><hr />\n<h2>Connections</h2>\n");
40578 - BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">\n");
40580 + BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" summary=\"Current connections\" id=\"clients\">\n");
40581 BUFFER_APPEND_STRING_CONST(b, "<tr>");
40582 mod_status_header_append_sort(b, p_d, "Client IP");
40583 mod_status_header_append_sort(b, p_d, "Read");
40584 @@ -473,16 +472,16 @@
40585 mod_status_header_append_sort(b, p_d, "URI");
40586 mod_status_header_append_sort(b, p_d, "File");
40587 BUFFER_APPEND_STRING_CONST(b, "</tr>\n");
40590 for (j = 0; j < srv->conns->used; j++) {
40591 connection *c = srv->conns->ptr[j];
40593 - BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string\">");
40596 + BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string ip\">");
40598 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr)));
40600 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40603 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_read\">");
40605 if (con->request.content_length) {
40606 buffer_append_long(b, c->request_content_queue->bytes_in);
40607 BUFFER_APPEND_STRING_CONST(b, "/");
40608 @@ -490,55 +489,55 @@
40610 BUFFER_APPEND_STRING_CONST(b, "0/0");
40613 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40616 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_written\">");
40618 buffer_append_off_t(b, chunkqueue_written(c->write_queue));
40619 BUFFER_APPEND_STRING_CONST(b, "/");
40620 buffer_append_off_t(b, chunkqueue_length(c->write_queue));
40622 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40625 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string state\">");
40627 buffer_append_string(b, connection_get_state(c->state));
40629 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40632 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int time\">");
40634 buffer_append_long(b, srv->cur_ts - c->request_start);
40636 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40639 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string host\">");
40641 if (buffer_is_empty(c->server_name)) {
40642 buffer_append_string_buffer(b, c->uri.authority);
40645 buffer_append_string_buffer(b, c->server_name);
40648 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40651 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string uri\">");
40653 if (!buffer_is_empty(c->uri.path)) {
40654 buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML);
40657 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40660 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string file\">");
40662 buffer_append_string_buffer(b, c->physical.path);
40665 BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40669 - BUFFER_APPEND_STRING_CONST(b,
40672 + BUFFER_APPEND_STRING_CONST(b,
40676 - BUFFER_APPEND_STRING_CONST(b,
40679 + BUFFER_APPEND_STRING_CONST(b,
40685 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
40691 @@ -548,7 +547,7 @@
40697 b = chunkqueue_get_append_buffer(con->write_queue);
40699 /* output total number of requests */
40700 @@ -556,19 +555,19 @@
40701 avg = p->abs_requests;
40702 buffer_append_long(b, avg);
40703 BUFFER_APPEND_STRING_CONST(b, "\n");
40706 /* output total traffic out in kbytes */
40707 BUFFER_APPEND_STRING_CONST(b, "Total kBytes: ");
40708 avg = p->abs_traffic_out / 1024;
40709 buffer_append_long(b, avg);
40710 BUFFER_APPEND_STRING_CONST(b, "\n");
40713 /* output uptime */
40714 BUFFER_APPEND_STRING_CONST(b, "Uptime: ");
40715 ts = srv->cur_ts - srv->startup_ts;
40716 buffer_append_long(b, ts);
40717 BUFFER_APPEND_STRING_CONST(b, "\n");
40720 /* output busy servers */
40721 BUFFER_APPEND_STRING_CONST(b, "BusyServers: ");
40722 buffer_append_long(b, srv->conns->used);
40723 @@ -577,7 +576,7 @@
40724 /* set text/plain output */
40726 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
40732 @@ -591,10 +590,10 @@
40733 /* we have nothing to send */
40734 con->http_status = 204;
40735 con->file_finished = 1;
40738 return HANDLER_FINISHED;
40742 b = chunkqueue_get_append_buffer(con->write_queue);
40744 for (i = 0; i < st->used; i++) {
40745 @@ -605,27 +604,27 @@
40746 buffer_append_long(b, ((data_integer *)(st->data[ndx]))->value);
40747 buffer_append_string(b, "\n");
40751 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
40754 con->http_status = 200;
40755 con->file_finished = 1;
40758 return HANDLER_FINISHED;
40762 static handler_t mod_status_handle_server_status(server *srv, connection *con, void *p_d) {
40765 if (buffer_is_equal_string(con->uri.query, CONST_STR_LEN("auto"))) {
40766 mod_status_handle_server_status_text(srv, con, p_d);
40768 mod_status_handle_server_status_html(srv, con, p_d);
40772 con->http_status = 200;
40773 con->file_finished = 1;
40776 return HANDLER_FINISHED;
40779 @@ -634,9 +633,9 @@
40780 plugin_data *p = p_d;
40781 buffer *b, *m = p->module_list;
40784 - struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
40787 + struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
40789 /* - poll is most reliable
40790 * - select works everywhere
40791 * - linux-* are experimental
40792 @@ -661,10 +660,10 @@
40794 { FDEVENT_HANDLER_UNSET, NULL }
40798 b = chunkqueue_get_append_buffer(con->write_queue);
40800 - BUFFER_COPY_STRING_CONST(b,
40802 + BUFFER_COPY_STRING_CONST(b,
40803 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
40804 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
40805 " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
40806 @@ -675,7 +674,7 @@
40808 " <h1>" PACKAGE_NAME " " PACKAGE_VERSION "</h1>\n"
40809 " <table border=\"1\">\n");
40812 mod_status_header_append(b, "Server-Features");
40814 mod_status_row_append(b, "RegEx Conditionals", "enabled");
40815 @@ -683,21 +682,21 @@
40816 mod_status_row_append(b, "RegEx Conditionals", "disabled - pcre missing");
40818 mod_status_header_append(b, "Network Engine");
40821 for (i = 0; event_handlers[i].name; i++) {
40822 if (event_handlers[i].et == srv->event_handler) {
40823 mod_status_row_append(b, "fd-Event-Handler", event_handlers[i].name);
40829 mod_status_header_append(b, "Config-File-Settings");
40832 for (i = 0; i < srv->plugins.used; i++) {
40833 plugin **ps = srv->plugins.ptr;
40836 plugin *pl = ps[i];
40840 buffer_copy_string_buffer(m, pl->name);
40842 @@ -705,137 +704,135 @@
40843 buffer_append_string_buffer(m, pl->name);
40848 mod_status_row_append(b, "Loaded Modules", m->ptr);
40851 BUFFER_APPEND_STRING_CONST(b, " </table>\n");
40853 - BUFFER_APPEND_STRING_CONST(b,
40855 + BUFFER_APPEND_STRING_CONST(b,
40861 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
40864 con->http_status = 200;
40865 con->file_finished = 1;
40868 return HANDLER_FINISHED;
40871 -#define PATCH(x) \
40872 - p->conf.x = s->x;
40873 static int mod_status_patch_connection(server *srv, connection *con, plugin_data *p) {
40875 plugin_config *s = p->config_storage[0];
40877 - PATCH(status_url);
40878 - PATCH(config_url);
40880 - PATCH(statistics_url);
40883 + PATCH_OPTION(status_url);
40884 + PATCH_OPTION(config_url);
40885 + PATCH_OPTION(sort);
40886 + PATCH_OPTION(statistics_url);
40888 /* skip the first, the global context */
40889 for (i = 1; i < srv->config_context->used; i++) {
40890 data_config *dc = (data_config *)srv->config_context->data[i];
40891 s = p->config_storage[i];
40894 /* condition didn't match */
40895 if (!config_check_cond(srv, con, dc)) continue;
40899 for (j = 0; j < dc->value->used; j++) {
40900 data_unset *du = dc->value->data[j];
40903 if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.status-url"))) {
40904 - PATCH(status_url);
40905 + PATCH_OPTION(status_url);
40906 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.config-url"))) {
40907 - PATCH(config_url);
40908 + PATCH_OPTION(config_url);
40909 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.enable-sort"))) {
40911 + PATCH_OPTION(sort);
40912 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.statistics-url"))) {
40913 - PATCH(statistics_url);
40915 + PATCH_OPTION(statistics_url);
40924 static handler_t mod_status_handler(server *srv, connection *con, void *p_d) {
40925 plugin_data *p = p_d;
40928 mod_status_patch_connection(srv, con, p);
40930 - if (!buffer_is_empty(p->conf.status_url) &&
40932 + if (!buffer_is_empty(p->conf.status_url) &&
40933 buffer_is_equal(p->conf.status_url, con->uri.path)) {
40934 return mod_status_handle_server_status(srv, con, p_d);
40935 - } else if (!buffer_is_empty(p->conf.config_url) &&
40936 + } else if (!buffer_is_empty(p->conf.config_url) &&
40937 buffer_is_equal(p->conf.config_url, con->uri.path)) {
40938 return mod_status_handle_server_config(srv, con, p_d);
40939 - } else if (!buffer_is_empty(p->conf.statistics_url) &&
40940 + } else if (!buffer_is_empty(p->conf.statistics_url) &&
40941 buffer_is_equal(p->conf.statistics_url, con->uri.path)) {
40942 return mod_status_handle_server_statistics(srv, con, p_d);
40946 return HANDLER_GO_ON;
40949 TRIGGER_FUNC(mod_status_trigger) {
40950 plugin_data *p = p_d;
40954 /* check all connections */
40955 for (i = 0; i < srv->conns->used; i++) {
40956 connection *c = srv->conns->ptr[i];
40959 p->bytes_written += c->bytes_written_cur_second;
40963 /* a sliding average */
40964 p->mod_5s_traffic_out[p->mod_5s_ndx] = p->bytes_written;
40965 p->mod_5s_requests [p->mod_5s_ndx] = p->requests;
40968 p->mod_5s_ndx = (p->mod_5s_ndx+1) % 5;
40971 p->abs_traffic_out += p->bytes_written;
40972 p->rel_traffic_out += p->bytes_written;
40975 p->bytes_written = 0;
40978 /* reset storage - second */
40979 p->traffic_out = 0;
40983 return HANDLER_GO_ON;
40986 REQUESTDONE_FUNC(mod_status_account) {
40987 plugin_data *p = p_d;
40997 p->bytes_written += con->bytes_written_cur_second;
41000 return HANDLER_GO_ON;
41003 int mod_status_plugin_init(plugin *p) {
41004 p->version = LIGHTTPD_VERSION_ID;
41005 p->name = buffer_init_string("status");
41008 p->init = mod_status_init;
41009 p->cleanup = mod_status_free;
41010 p->set_defaults= mod_status_set_defaults;
41013 p->handle_uri_clean = mod_status_handler;
41014 p->handle_trigger = mod_status_trigger;
41015 p->handle_request_done = mod_status_account;
41023 --- ../lighttpd-1.4.11/src/mod_trigger_b4_dl.c 2005-09-23 22:53:55.000000000 +0300
41024 +++ lighttpd-1.4.12/src/mod_trigger_b4_dl.c 2006-07-16 00:26:03.000000000 +0300
41025 @@ -24,18 +24,18 @@
41028 * this is a trigger_b4_dl for a lighttpd plugin
41033 /* plugin config for all request/connections */
41036 buffer *db_filename;
41039 buffer *trigger_url;
41040 buffer *download_url;
41045 buffer *mc_namespace;
41046 #if defined(HAVE_PCRE_H)
41047 @@ -46,58 +46,58 @@
41051 -#if defined(HAVE_MEMCACHE_H)
41052 +#if defined(HAVE_MEMCACHE_H)
41053 struct memcache *mc;
41057 unsigned short trigger_timeout;
41058 unsigned short debug;
41068 plugin_config **config_storage;
41070 - plugin_config conf;
41072 + plugin_config conf;
41075 /* init the plugin data */
41076 INIT_FUNC(mod_trigger_b4_dl_init) {
41080 p = calloc(1, sizeof(*p));
41083 p->tmp_buf = buffer_init();
41089 /* detroy the plugin data */
41090 FREE_FUNC(mod_trigger_b4_dl_free) {
41091 plugin_data *p = p_d;
41096 if (!p) return HANDLER_GO_ON;
41099 if (p->config_storage) {
41101 for (i = 0; i < srv->config_context->used; i++) {
41102 plugin_config *s = p->config_storage[i];
41107 buffer_free(s->db_filename);
41108 buffer_free(s->download_url);
41109 buffer_free(s->trigger_url);
41110 buffer_free(s->deny_url);
41113 buffer_free(s->mc_namespace);
41114 array_free(s->mc_hosts);
41117 #if defined(HAVE_PCRE_H)
41118 if (s->trigger_regex) pcre_free(s->trigger_regex);
41119 if (s->download_regex) pcre_free(s->download_regex);
41120 @@ -108,16 +108,16 @@
41121 #if defined(HAVE_MEMCACHE_H)
41122 if (s->mc) mc_free(s->mc);
41128 free(p->config_storage);
41132 buffer_free(p->tmp_buf);
41138 return HANDLER_GO_ON;
41141 @@ -126,9 +126,9 @@
41142 SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
41143 plugin_data *p = p_d;
41147 - config_values_t cv[] = {
41150 + config_values_t cv[] = {
41151 { "trigger-before-download.gdbm-filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
41152 { "trigger-before-download.trigger-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
41153 { "trigger-before-download.download-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
41154 @@ -139,18 +139,18 @@
41155 { "trigger-before-download.debug", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
41156 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
41160 if (!p) return HANDLER_ERROR;
41163 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
41166 for (i = 0; i < srv->config_context->used; i++) {
41168 #if defined(HAVE_PCRE_H)
41169 const char *errptr;
41174 s = calloc(1, sizeof(plugin_config));
41175 s->db_filename = buffer_init();
41176 s->download_url = buffer_init();
41177 @@ -158,7 +158,7 @@
41178 s->deny_url = buffer_init();
41179 s->mc_hosts = array_init();
41180 s->mc_namespace = buffer_init();
41183 cv[0].destination = s->db_filename;
41184 cv[1].destination = s->trigger_url;
41185 cv[2].destination = s->download_url;
41186 @@ -167,41 +167,41 @@
41187 cv[5].destination = s->mc_hosts;
41188 cv[6].destination = s->mc_namespace;
41189 cv[7].destination = &(s->debug);
41192 p->config_storage[i] = s;
41195 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
41196 return HANDLER_ERROR;
41198 #if defined(HAVE_GDBM_H)
41199 if (!buffer_is_empty(s->db_filename)) {
41200 if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) {
41201 - log_error_write(srv, __FILE__, __LINE__, "s",
41202 + log_error_write(srv, __FILE__, __LINE__, "s",
41203 "gdbm-open failed");
41204 return HANDLER_ERROR;
41208 -#if defined(HAVE_PCRE_H)
41209 +#if defined(HAVE_PCRE_H)
41210 if (!buffer_is_empty(s->download_url)) {
41211 if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr,
41212 0, &errptr, &erroff, NULL))) {
41214 - log_error_write(srv, __FILE__, __LINE__, "sbss",
41215 - "compiling regex for download-url failed:",
41217 + log_error_write(srv, __FILE__, __LINE__, "sbss",
41218 + "compiling regex for download-url failed:",
41219 s->download_url, "pos:", erroff);
41220 return HANDLER_ERROR;
41225 if (!buffer_is_empty(s->trigger_url)) {
41226 if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr,
41227 0, &errptr, &erroff, NULL))) {
41229 - log_error_write(srv, __FILE__, __LINE__, "sbss",
41230 - "compiling regex for trigger-url failed:",
41232 + log_error_write(srv, __FILE__, __LINE__, "sbss",
41233 + "compiling regex for trigger-url failed:",
41234 s->trigger_url, "pos:", erroff);
41237 return HANDLER_ERROR;
41240 @@ -211,100 +211,97 @@
41241 #if defined(HAVE_MEMCACHE_H)
41246 for (k = 0; k < s->mc_hosts->used; k++) {
41247 data_string *ds = (data_string *)s->mc_hosts->data[k];
41250 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
41251 - log_error_write(srv, __FILE__, __LINE__, "sb",
41252 - "connection to host failed:",
41253 + log_error_write(srv, __FILE__, __LINE__, "sb",
41254 + "connection to host failed:",
41258 return HANDLER_ERROR;
41262 - log_error_write(srv, __FILE__, __LINE__, "s",
41263 + log_error_write(srv, __FILE__, __LINE__, "s",
41264 "memcache support is not compiled in but trigger-before-download.memcache-hosts is set, aborting");
41265 return HANDLER_ERROR;
41271 #if (!defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)) || !defined(HAVE_PCRE_H)
41272 - log_error_write(srv, __FILE__, __LINE__, "s",
41273 + log_error_write(srv, __FILE__, __LINE__, "s",
41274 "(either gdbm or libmemcache) and pcre are require, but were not found, aborting");
41275 return HANDLER_ERROR;
41280 return HANDLER_GO_ON;
41283 -#define PATCH(x) \
41284 - p->conf.x = s->x;
41285 static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plugin_data *p) {
41287 plugin_config *s = p->config_storage[0];
41290 #if defined(HAVE_GDBM)
41293 + PATCH_OPTION(db);
41295 #if defined(HAVE_PCRE_H)
41296 - PATCH(download_regex);
41297 - PATCH(trigger_regex);
41299 - PATCH(trigger_timeout);
41301 - PATCH(mc_namespace);
41303 + PATCH_OPTION(download_regex);
41304 + PATCH_OPTION(trigger_regex);
41306 + PATCH_OPTION(trigger_timeout);
41307 + PATCH_OPTION(deny_url);
41308 + PATCH_OPTION(mc_namespace);
41309 + PATCH_OPTION(debug);
41310 #if defined(HAVE_MEMCACHE_H)
41312 + PATCH_OPTION(mc);
41316 /* skip the first, the global context */
41317 for (i = 1; i < srv->config_context->used; i++) {
41318 data_config *dc = (data_config *)srv->config_context->data[i];
41319 s = p->config_storage[i];
41322 /* condition didn't match */
41323 if (!config_check_cond(srv, con, dc)) continue;
41327 for (j = 0; j < dc->value->used; j++) {
41328 data_unset *du = dc->value->data[j];
41330 if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.download-url"))) {
41331 #if defined(HAVE_PCRE_H)
41332 - PATCH(download_regex);
41333 + PATCH_OPTION(download_regex);
41335 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-url"))) {
41336 # if defined(HAVE_PCRE_H)
41337 - PATCH(trigger_regex);
41338 + PATCH_OPTION(trigger_regex);
41340 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.gdbm-filename"))) {
41341 #if defined(HAVE_GDBM_H)
41343 + PATCH_OPTION(db);
41345 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-timeout"))) {
41346 - PATCH(trigger_timeout);
41347 + PATCH_OPTION(trigger_timeout);
41348 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.debug"))) {
41350 + PATCH_OPTION(debug);
41351 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.deny-url"))) {
41353 + PATCH_OPTION(deny_url);
41354 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-namespace"))) {
41355 - PATCH(mc_namespace);
41356 + PATCH_OPTION(mc_namespace);
41357 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-hosts"))) {
41358 #if defined(HAVE_MEMCACHE_H)
41360 + PATCH_OPTION(mc);
41371 URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
41372 plugin_data *p = p_d;
41373 @@ -315,20 +312,20 @@
41379 if (con->uri.path->used == 0) return HANDLER_GO_ON;
41382 mod_trigger_b4_dl_patch_connection(srv, con, p);
41385 if (!p->conf.trigger_regex || !p->conf.download_regex) return HANDLER_GO_ON;
41388 # if !defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)
41389 return HANDLER_GO_ON;
41390 # elif defined(HAVE_GDBM_H) && defined(HAVE_MEMCACHE_H)
41391 if (!p->conf.db && !p->conf.mc) return HANDLER_GO_ON;
41392 if (p->conf.db && p->conf.mc) {
41393 /* can't decide which one */
41396 return HANDLER_GO_ON;
41398 # elif defined(HAVE_GDBM_H)
41399 @@ -336,12 +333,12 @@
41401 if (!p->conf.mc) return HANDLER_GO_ON;
41405 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "X-Forwarded-For"))) {
41406 /* X-Forwarded-For contains the ip behind the proxy */
41409 remote_ip = ds->value->ptr;
41412 /* memcache can't handle spaces */
41414 remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
41415 @@ -350,13 +347,13 @@
41416 if (p->conf.debug) {
41417 log_error_write(srv, __FILE__, __LINE__, "ss", "(debug) remote-ip:", remote_ip);
41421 /* check if URL is a trigger -> insert IP into DB */
41422 if ((n = pcre_exec(p->conf.trigger_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
41423 if (n != PCRE_ERROR_NOMATCH) {
41424 log_error_write(srv, __FILE__, __LINE__, "sd",
41425 "execution error while matching:", n);
41428 return HANDLER_ERROR;
41431 @@ -364,34 +361,34 @@
41433 /* the trigger matched */
41437 key.dptr = (char *)remote_ip;
41438 key.dsize = strlen(remote_ip);
41441 val.dptr = (char *)&(srv->cur_ts);
41442 val.dsize = sizeof(srv->cur_ts);
41445 if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
41446 log_error_write(srv, __FILE__, __LINE__, "s",
41451 -# if defined(HAVE_MEMCACHE_H)
41452 +# if defined(HAVE_MEMCACHE_H)
41455 buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
41456 buffer_append_string(p->tmp_buf, remote_ip);
41459 for (i = 0; i < p->tmp_buf->used - 1; i++) {
41460 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
41464 if (p->conf.debug) {
41465 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) triggered IP:", p->tmp_buf);
41468 - if (0 != mc_set(p->conf.mc,
41469 + if (0 != mc_set(p->conf.mc,
41470 CONST_BUF_LEN(p->tmp_buf),
41471 (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
41472 p->conf.trigger_timeout, 0)) {
41473 @@ -401,7 +398,7 @@
41479 /* check if URL is a download -> check IP in DB, update timestamp */
41480 if ((n = pcre_exec(p->conf.download_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
41481 if (n != PCRE_ERROR_NOMATCH) {
41482 @@ -411,93 +408,93 @@
41485 /* the download uri matched */
41486 -# if defined(HAVE_GDBM_H)
41487 +# if defined(HAVE_GDBM_H)
41493 key.dptr = (char *)remote_ip;
41494 key.dsize = strlen(remote_ip);
41497 val = gdbm_fetch(p->conf.db, key);
41500 if (val.dptr == NULL) {
41501 /* not found, redirect */
41504 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41507 con->http_status = 307;
41510 return HANDLER_FINISHED;
41514 last_hit = *(time_t *)(val.dptr);
41520 if (srv->cur_ts - last_hit > p->conf.trigger_timeout) {
41521 /* found, but timeout, redirect */
41524 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41525 con->http_status = 307;
41529 if (0 != gdbm_delete(p->conf.db, key)) {
41530 log_error_write(srv, __FILE__, __LINE__, "s",
41536 return HANDLER_FINISHED;
41540 val.dptr = (char *)&(srv->cur_ts);
41541 val.dsize = sizeof(srv->cur_ts);
41544 if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
41545 log_error_write(srv, __FILE__, __LINE__, "s",
41551 -# if defined(HAVE_MEMCACHE_H)
41553 +# if defined(HAVE_MEMCACHE_H)
41559 buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
41560 buffer_append_string(p->tmp_buf, remote_ip);
41563 for (i = 0; i < p->tmp_buf->used - 1; i++) {
41564 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
41568 if (p->conf.debug) {
41569 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) checking IP:", p->tmp_buf);
41575 * memcached is do expiration for us, as long as we can fetch it every thing is ok
41576 - * and the timestamp is updated
41578 + * and the timestamp is updated
41581 - if (NULL == (r = mc_aget(p->conf.mc,
41582 + if (NULL == (r = mc_aget(p->conf.mc,
41583 CONST_BUF_LEN(p->tmp_buf)
41587 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41590 con->http_status = 307;
41593 return HANDLER_FINISHED;
41600 /* set a new timeout */
41601 - if (0 != mc_set(p->conf.mc,
41602 + if (0 != mc_set(p->conf.mc,
41603 CONST_BUF_LEN(p->tmp_buf),
41604 (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
41605 p->conf.trigger_timeout, 0)) {
41606 @@ -507,13 +504,13 @@
41619 return HANDLER_GO_ON;
41622 @@ -521,21 +518,21 @@
41623 TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
41624 plugin_data *p = p_d;
41628 /* check DB each minute */
41629 if (srv->cur_ts % 60 != 0) return HANDLER_GO_ON;
41633 for (i = 0; i < srv->config_context->used; i++) {
41634 plugin_config *s = p->config_storage[i];
41635 datum key, val, okey;
41638 if (!s->db) continue;
41643 - /* according to the manual this loop + delete does delete all entries on its way
41646 + /* according to the manual this loop + delete does delete all entries on its way
41648 * we don't care as the next round will remove them. We don't have to perfect here.
41650 for (key = gdbm_firstkey(s->db); key.dptr; key = gdbm_nextkey(s->db, okey)) {
41651 @@ -544,21 +541,21 @@
41657 val = gdbm_fetch(s->db, key);
41660 last_hit = *(time_t *)(val.dptr);
41666 if (srv->cur_ts - last_hit > s->trigger_timeout) {
41667 gdbm_delete(s->db, key);
41673 if (okey.dptr) free(okey.dptr);
41676 /* reorg once a day */
41677 if ((srv->cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(s->db);
41679 @@ -571,7 +568,7 @@
41680 int mod_trigger_b4_dl_plugin_init(plugin *p) {
41681 p->version = LIGHTTPD_VERSION_ID;
41682 p->name = buffer_init_string("trigger_b4_dl");
41685 p->init = mod_trigger_b4_dl_init;
41686 p->handle_uri_clean = mod_trigger_b4_dl_uri_handler;
41687 p->set_defaults = mod_trigger_b4_dl_set_defaults;
41688 @@ -579,8 +576,8 @@
41689 p->handle_trigger = mod_trigger_b4_dl_handle_trigger;
41691 p->cleanup = mod_trigger_b4_dl_free;
41699 --- ../lighttpd-1.4.11/src/mod_userdir.c 2005-10-28 16:48:28.000000000 +0300
41700 +++ lighttpd-1.4.12/src/mod_userdir.c 2006-07-16 00:26:04.000000000 +0300
41702 #include "response.h"
41704 #include "plugin.h"
41705 +#include "sys-files.h"
41709 @@ -25,54 +26,54 @@
41719 plugin_config **config_storage;
41721 - plugin_config conf;
41723 + plugin_config conf;
41726 /* init the plugin data */
41727 INIT_FUNC(mod_userdir_init) {
41731 p = calloc(1, sizeof(*p));
41734 p->username = buffer_init();
41735 p->temp_path = buffer_init();
41741 /* detroy the plugin data */
41742 FREE_FUNC(mod_userdir_free) {
41743 plugin_data *p = p_d;
41746 if (!p) return HANDLER_GO_ON;
41749 if (p->config_storage) {
41753 for (i = 0; i < srv->config_context->used; i++) {
41754 plugin_config *s = p->config_storage[i];
41757 array_free(s->include_user);
41758 array_free(s->exclude_user);
41759 buffer_free(s->path);
41760 buffer_free(s->basepath);
41765 free(p->config_storage);
41769 buffer_free(p->username);
41770 buffer_free(p->temp_path);
41776 return HANDLER_GO_ON;
41779 @@ -81,81 +82,78 @@
41780 SETDEFAULTS_FUNC(mod_userdir_set_defaults) {
41781 plugin_data *p = p_d;
41784 - config_values_t cv[] = {
41786 + config_values_t cv[] = {
41787 { "userdir.path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
41788 { "userdir.exclude-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
41789 { "userdir.include-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
41790 { "userdir.basepath", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
41791 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
41795 if (!p) return HANDLER_ERROR;
41798 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
41801 for (i = 0; i < srv->config_context->used; i++) {
41805 s = calloc(1, sizeof(plugin_config));
41806 s->exclude_user = array_init();
41807 s->include_user = array_init();
41808 s->path = buffer_init();
41809 s->basepath = buffer_init();
41812 cv[0].destination = s->path;
41813 cv[1].destination = s->exclude_user;
41814 cv[2].destination = s->include_user;
41815 cv[3].destination = s->basepath;
41818 p->config_storage[i] = s;
41821 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
41822 return HANDLER_ERROR;
41827 return HANDLER_GO_ON;
41830 -#define PATCH(x) \
41831 - p->conf.x = s->x;
41832 static int mod_userdir_patch_connection(server *srv, connection *con, plugin_data *p) {
41834 plugin_config *s = p->config_storage[0];
41837 - PATCH(exclude_user);
41838 - PATCH(include_user);
41842 + PATCH_OPTION(path);
41843 + PATCH_OPTION(exclude_user);
41844 + PATCH_OPTION(include_user);
41845 + PATCH_OPTION(basepath);
41847 /* skip the first, the global context */
41848 for (i = 1; i < srv->config_context->used; i++) {
41849 data_config *dc = (data_config *)srv->config_context->data[i];
41850 s = p->config_storage[i];
41853 /* condition didn't match */
41854 if (!config_check_cond(srv, con, dc)) continue;
41858 for (j = 0; j < dc->value->used; j++) {
41859 data_unset *du = dc->value->data[j];
41862 if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.path"))) {
41864 + PATCH_OPTION(path);
41865 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.exclude-user"))) {
41866 - PATCH(exclude_user);
41867 + PATCH_OPTION(exclude_user);
41868 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.include-user"))) {
41869 - PATCH(include_user);
41870 + PATCH_OPTION(include_user);
41871 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.basepath"))) {
41873 + PATCH_OPTION(basepath);
41883 URIHANDLER_FUNC(mod_userdir_docroot_handler) {
41884 plugin_data *p = p_d;
41885 @@ -169,18 +167,18 @@
41886 if (con->uri.path->used == 0) return HANDLER_GO_ON;
41888 mod_userdir_patch_connection(srv, con, p);
41891 uri_len = con->uri.path->used - 1;
41894 /* /~user/foo.html -> /home/user/public_html/foo.html */
41897 if (con->uri.path->ptr[0] != '/' ||
41898 con->uri.path->ptr[1] != '~') return HANDLER_GO_ON;
41901 if (NULL == (rel_url = strchr(con->uri.path->ptr + 2, '/'))) {
41902 /* / is missing -> redirect to .../ as we are a user - DIRECTORY ! :) */
41903 http_response_redirect_to_directory(srv, con);
41906 return HANDLER_FINISHED;
41909 @@ -188,10 +186,10 @@
41910 if (0 == rel_url - (con->uri.path->ptr + 2)) {
41911 return HANDLER_GO_ON;
41915 buffer_copy_string_len(p->username, con->uri.path->ptr + 2, rel_url - (con->uri.path->ptr + 2));
41917 - if (buffer_is_empty(p->conf.basepath)
41919 + if (buffer_is_empty(p->conf.basepath)
41921 && NULL == (pwd = getpwnam(p->username->ptr))
41923 @@ -200,31 +198,31 @@
41924 return HANDLER_GO_ON;
41929 for (k = 0; k < p->conf.exclude_user->used; k++) {
41930 data_string *ds = (data_string *)p->conf.exclude_user->data[k];
41933 if (buffer_is_equal(ds->value, p->username)) {
41934 /* user in exclude list */
41935 return HANDLER_GO_ON;
41940 if (p->conf.include_user->used) {
41941 int found_user = 0;
41942 for (k = 0; k < p->conf.include_user->used; k++) {
41943 data_string *ds = (data_string *)p->conf.include_user->data[k];
41946 if (buffer_is_equal(ds->value, p->username)) {
41947 /* user in include list */
41954 if (!found_user) return HANDLER_GO_ON;
41958 /* we build the physical path */
41960 if (buffer_is_empty(p->conf.basepath)) {
41961 @@ -252,23 +250,23 @@
41964 buffer_copy_string_buffer(p->temp_path, p->conf.basepath);
41965 - BUFFER_APPEND_SLASH(p->temp_path);
41966 + PATHNAME_APPEND_SLASH(p->temp_path);
41967 buffer_append_string_buffer(p->temp_path, p->username);
41969 - BUFFER_APPEND_SLASH(p->temp_path);
41970 - buffer_append_string_buffer(p->temp_path, p->conf.path);
41971 + PATHNAME_APPEND_SLASH(p->temp_path);
41972 + buffer_append_string_buffer(p->temp_path, p->conf.path);
41974 if (buffer_is_empty(p->conf.basepath)) {
41979 ret = stat(p->temp_path->ptr, &st);
41980 if (ret < 0 || S_ISDIR(st.st_mode) != 1) {
41981 return HANDLER_GO_ON;
41986 - BUFFER_APPEND_SLASH(p->temp_path);
41987 + PATHNAME_APPEND_SLASH(p->temp_path);
41988 buffer_append_string(p->temp_path, rel_url + 1); /* skip the / */
41989 buffer_copy_string_buffer(con->physical.path, p->temp_path);
41991 @@ -282,13 +280,13 @@
41992 int mod_userdir_plugin_init(plugin *p) {
41993 p->version = LIGHTTPD_VERSION_ID;
41994 p->name = buffer_init_string("userdir");
41997 p->init = mod_userdir_init;
41998 p->handle_physical = mod_userdir_docroot_handler;
41999 p->set_defaults = mod_userdir_set_defaults;
42000 p->cleanup = mod_userdir_free;
42008 --- ../lighttpd-1.4.11/src/mod_usertrack.c 2006-01-31 15:01:20.000000000 +0200
42009 +++ lighttpd-1.4.12/src/mod_usertrack.c 2006-07-16 00:26:04.000000000 +0300
42010 @@ -24,44 +24,44 @@
42016 plugin_config **config_storage;
42018 - plugin_config conf;
42020 + plugin_config conf;
42023 /* init the plugin data */
42024 INIT_FUNC(mod_usertrack_init) {
42028 p = calloc(1, sizeof(*p));
42034 /* detroy the plugin data */
42035 FREE_FUNC(mod_usertrack_free) {
42036 plugin_data *p = p_d;
42042 if (!p) return HANDLER_GO_ON;
42045 if (p->config_storage) {
42047 for (i = 0; i < srv->config_context->used; i++) {
42048 plugin_config *s = p->config_storage[i];
42051 buffer_free(s->cookie_name);
42052 buffer_free(s->cookie_domain);
42057 free(p->config_storage);
42064 return HANDLER_GO_ON;
42067 @@ -70,38 +70,38 @@
42068 SETDEFAULTS_FUNC(mod_usertrack_set_defaults) {
42069 plugin_data *p = p_d;
42072 - config_values_t cv[] = {
42074 + config_values_t cv[] = {
42075 { "usertrack.cookie-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
42076 { "usertrack.cookie-max-age", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
42077 { "usertrack.cookie-domain", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
42079 - { "usertrack.cookiename", NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },
42081 + { "usertrack.cookiename", NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },
42082 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42086 if (!p) return HANDLER_ERROR;
42089 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42092 for (i = 0; i < srv->config_context->used; i++) {
42096 s = calloc(1, sizeof(plugin_config));
42097 s->cookie_name = buffer_init();
42098 s->cookie_domain = buffer_init();
42099 s->cookie_max_age = 0;
42102 cv[0].destination = s->cookie_name;
42103 cv[1].destination = &(s->cookie_max_age);
42104 cv[2].destination = s->cookie_domain;
42107 p->config_storage[i] = s;
42110 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42111 return HANDLER_ERROR;
42115 if (buffer_is_empty(s->cookie_name)) {
42116 buffer_copy_string(s->cookie_name, "TRACKID");
42118 @@ -109,68 +109,65 @@
42119 for (j = 0; j < s->cookie_name->used - 1; j++) {
42120 char c = s->cookie_name->ptr[j] | 32;
42121 if (c < 'a' || c > 'z') {
42122 - log_error_write(srv, __FILE__, __LINE__, "sb",
42123 - "invalid character in usertrack.cookie-name:",
42124 + log_error_write(srv, __FILE__, __LINE__, "sb",
42125 + "invalid character in usertrack.cookie-name:",
42129 return HANDLER_ERROR;
42135 if (!buffer_is_empty(s->cookie_domain)) {
42137 for (j = 0; j < s->cookie_domain->used - 1; j++) {
42138 char c = s->cookie_domain->ptr[j];
42139 if (c <= 32 || c >= 127 || c == '"' || c == '\\') {
42140 - log_error_write(srv, __FILE__, __LINE__, "sb",
42141 - "invalid character in usertrack.cookie-domain:",
42142 + log_error_write(srv, __FILE__, __LINE__, "sb",
42143 + "invalid character in usertrack.cookie-domain:",
42147 return HANDLER_ERROR;
42154 return HANDLER_GO_ON;
42157 -#define PATCH(x) \
42158 - p->conf.x = s->x;
42159 static int mod_usertrack_patch_connection(server *srv, connection *con, plugin_data *p) {
42161 plugin_config *s = p->config_storage[0];
42163 - PATCH(cookie_name);
42164 - PATCH(cookie_domain);
42165 - PATCH(cookie_max_age);
42168 + PATCH_OPTION(cookie_name);
42169 + PATCH_OPTION(cookie_domain);
42170 + PATCH_OPTION(cookie_max_age);
42172 /* skip the first, the global context */
42173 for (i = 1; i < srv->config_context->used; i++) {
42174 data_config *dc = (data_config *)srv->config_context->data[i];
42175 s = p->config_storage[i];
42178 /* condition didn't match */
42179 if (!config_check_cond(srv, con, dc)) continue;
42183 for (j = 0; j < dc->value->used; j++) {
42184 data_unset *du = dc->value->data[j];
42187 if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-name"))) {
42188 - PATCH(cookie_name);
42189 + PATCH_OPTION(cookie_name);
42190 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-max-age"))) {
42191 - PATCH(cookie_max_age);
42192 + PATCH_OPTION(cookie_max_age);
42193 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-domain"))) {
42194 - PATCH(cookie_domain);
42195 + PATCH_OPTION(cookie_domain);
42205 URIHANDLER_FUNC(mod_usertrack_uri_handler) {
42206 plugin_data *p = p_d;
42207 @@ -178,38 +175,38 @@
42208 unsigned char h[16];
42213 if (con->uri.path->used == 0) return HANDLER_GO_ON;
42216 mod_usertrack_patch_connection(srv, con, p);
42219 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
42221 /* we have a cookie, does it contain a valid name ? */
42223 - /* parse the cookie
42226 + /* parse the cookie
42228 * check for cookiename + (WS | '=')
42234 if (NULL != (g = strstr(ds->value->ptr, p->conf.cookie_name->ptr))) {
42239 for (nc = g + p->conf.cookie_name->used-1; *nc == ' ' || *nc == '\t'; nc++);
42243 /* ok, found the key of our own cookie */
42246 if (strlen(nc) > 32) {
42248 return HANDLER_GO_ON;
42257 if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
42258 ds = data_response_init();
42259 @@ -217,39 +214,39 @@
42260 buffer_copy_string(ds->key, "Set-Cookie");
42261 buffer_copy_string_buffer(ds->value, p->conf.cookie_name);
42262 buffer_append_string(ds->value, "=");
42266 /* taken from mod_auth.c */
42269 /* generate shared-secret */
42271 MD5_Update(&Md5Ctx, (unsigned char *)con->uri.path->ptr, con->uri.path->used - 1);
42272 MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
42275 /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
42276 ltostr(hh, srv->cur_ts);
42277 MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
42278 ltostr(hh, rand());
42279 MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
42282 MD5_Final(h, &Md5Ctx);
42285 buffer_append_string_encoded(ds->value, (char *)h, 16, ENCODING_HEX);
42286 buffer_append_string(ds->value, "; Path=/");
42287 buffer_append_string(ds->value, "; Version=1");
42290 if (!buffer_is_empty(p->conf.cookie_domain)) {
42291 buffer_append_string(ds->value, "; Domain=");
42292 buffer_append_string_encoded(ds->value, CONST_BUF_LEN(p->conf.cookie_domain), ENCODING_REL_URI);
42296 if (p->conf.cookie_max_age) {
42297 buffer_append_string(ds->value, "; max-age=");
42298 buffer_append_long(ds->value, p->conf.cookie_max_age);
42302 array_insert_unique(con->response.headers, (data_unset *)ds);
42305 return HANDLER_GO_ON;
42308 @@ -258,13 +255,13 @@
42309 int mod_usertrack_plugin_init(plugin *p) {
42310 p->version = LIGHTTPD_VERSION_ID;
42311 p->name = buffer_init_string("usertrack");
42314 p->init = mod_usertrack_init;
42315 p->handle_uri_clean = mod_usertrack_uri_handler;
42316 p->set_defaults = mod_usertrack_set_defaults;
42317 p->cleanup = mod_usertrack_free;
42325 --- ../lighttpd-1.4.11/src/mod_webdav.c 2006-03-03 01:28:58.000000000 +0200
42326 +++ lighttpd-1.4.12/src/mod_webdav.c 2006-07-18 13:03:40.000000000 +0300
42329 #include <stdlib.h>
42330 #include <string.h>
42331 -#include <dirent.h>
42333 -#include <unistd.h>
42336 #include <assert.h>
42337 -#include <sys/mman.h>
42339 #ifdef HAVE_CONFIG_H
42340 #include "config.h"
42342 #include <sqlite3.h>
42345 +#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H) && defined(HAVE_UUID_H)
42347 +#include <uuid/uuid.h>
42352 #include "buffer.h"
42353 @@ -33,13 +35,16 @@
42354 #include "stream.h"
42355 #include "stat_cache.h"
42357 +#include "sys-files.h"
42358 +#include "sys-mmap.h"
42359 +#include "sys-strings.h"
42362 * this is a webdav for a lighttpd plugin
42364 - * at least a very basic one.
42365 + * at least a very basic one.
42366 * - for now it is read-only and we only support PROPFIND
42372 @@ -58,64 +63,70 @@
42373 sqlite3_stmt *stmt_delete_prop;
42374 sqlite3_stmt *stmt_select_prop;
42375 sqlite3_stmt *stmt_select_propnames;
42378 sqlite3_stmt *stmt_delete_uri;
42379 sqlite3_stmt *stmt_move_uri;
42380 sqlite3_stmt *stmt_copy_uri;
42382 + sqlite3_stmt *stmt_remove_lock;
42383 + sqlite3_stmt *stmt_create_lock;
42384 + sqlite3_stmt *stmt_read_lock;
42385 + sqlite3_stmt *stmt_read_lock_by_uri;
42386 + sqlite3_stmt *stmt_refresh_lock;
42398 plugin_config **config_storage;
42400 - plugin_config conf;
42402 + plugin_config conf;
42405 /* init the plugin data */
42406 INIT_FUNC(mod_webdav_init) {
42410 p = calloc(1, sizeof(*p));
42413 p->tmp_buf = buffer_init();
42415 p->uri.scheme = buffer_init();
42416 p->uri.path_raw = buffer_init();
42417 p->uri.path = buffer_init();
42418 p->uri.authority = buffer_init();
42421 p->physical.path = buffer_init();
42422 p->physical.rel_path = buffer_init();
42423 p->physical.doc_root = buffer_init();
42424 p->physical.basedir = buffer_init();
42430 /* detroy the plugin data */
42431 FREE_FUNC(mod_webdav_free) {
42432 plugin_data *p = p_d;
42437 if (!p) return HANDLER_GO_ON;
42440 if (p->config_storage) {
42442 for (i = 0; i < srv->config_context->used; i++) {
42443 plugin_config *s = p->config_storage[i];
42448 buffer_free(s->sqlite_db_name);
42449 #ifdef USE_PROPPATCH
42452 sqlite3_finalize(s->stmt_delete_prop);
42453 sqlite3_finalize(s->stmt_delete_uri);
42454 sqlite3_finalize(s->stmt_copy_uri);
42455 @@ -123,9 +134,15 @@
42456 sqlite3_finalize(s->stmt_update_prop);
42457 sqlite3_finalize(s->stmt_select_prop);
42458 sqlite3_finalize(s->stmt_select_propnames);
42460 + sqlite3_finalize(s->stmt_read_lock);
42461 + sqlite3_finalize(s->stmt_read_lock_by_uri);
42462 + sqlite3_finalize(s->stmt_create_lock);
42463 + sqlite3_finalize(s->stmt_remove_lock);
42464 + sqlite3_finalize(s->stmt_refresh_lock);
42465 sqlite3_close(s->sql);
42471 free(p->config_storage);
42472 @@ -135,16 +152,16 @@
42473 buffer_free(p->uri.path_raw);
42474 buffer_free(p->uri.path);
42475 buffer_free(p->uri.authority);
42478 buffer_free(p->physical.path);
42479 buffer_free(p->physical.rel_path);
42480 buffer_free(p->physical.doc_root);
42481 buffer_free(p->physical.basedir);
42484 buffer_free(p->tmp_buf);
42490 return HANDLER_GO_ON;
42493 @@ -153,32 +170,32 @@
42494 SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
42495 plugin_data *p = p_d;
42498 - config_values_t cv[] = {
42500 + config_values_t cv[] = {
42501 { "webdav.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
42502 { "webdav.is-readonly", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
42503 { "webdav.sqlite-db-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
42504 { "webdav.log-xml", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
42505 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42509 if (!p) return HANDLER_ERROR;
42512 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42515 for (i = 0; i < srv->config_context->used; i++) {
42519 s = calloc(1, sizeof(plugin_config));
42520 s->sqlite_db_name = buffer_init();
42523 cv[0].destination = &(s->enabled);
42524 cv[1].destination = &(s->is_readonly);
42525 cv[2].destination = s->sqlite_db_name;
42526 cv[3].destination = &(s->log_xml);
42529 p->config_storage[i] = s;
42532 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42533 return HANDLER_ERROR;
42535 @@ -193,8 +210,26 @@
42536 return HANDLER_ERROR;
42539 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42540 - CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42541 + if (SQLITE_OK != sqlite3_exec(s->sql,
42542 + "CREATE TABLE properties ("
42543 + " resource TEXT NOT NULL,"
42544 + " prop TEXT NOT NULL,"
42545 + " ns TEXT NOT NULL,"
42546 + " value TEXT NOT NULL,"
42547 + " PRIMARY KEY(resource, prop, ns))",
42548 + NULL, NULL, &err)) {
42550 + if (0 != strcmp(err, "table properties already exists")) {
42551 + log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
42552 + sqlite3_free(err);
42554 + return HANDLER_ERROR;
42556 + sqlite3_free(err);
42559 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42560 + CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42561 &(s->stmt_select_prop), &next_stmt)) {
42562 /* prepare failed */
42564 @@ -202,8 +237,8 @@
42565 return HANDLER_ERROR;
42568 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42569 - CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"),
42570 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42571 + CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"),
42572 &(s->stmt_select_propnames), &next_stmt)) {
42573 /* prepare failed */
42575 @@ -211,16 +246,67 @@
42576 return HANDLER_ERROR;
42579 - if (SQLITE_OK != sqlite3_exec(s->sql,
42580 - "CREATE TABLE properties ("
42582 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42583 + CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"),
42584 + &(s->stmt_update_prop), &next_stmt)) {
42585 + /* prepare failed */
42587 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
42588 + return HANDLER_ERROR;
42591 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42592 + CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42593 + &(s->stmt_delete_prop), &next_stmt)) {
42594 + /* prepare failed */
42595 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42597 + return HANDLER_ERROR;
42600 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42601 + CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"),
42602 + &(s->stmt_delete_uri), &next_stmt)) {
42603 + /* prepare failed */
42604 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42606 + return HANDLER_ERROR;
42609 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42610 + CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"),
42611 + &(s->stmt_copy_uri), &next_stmt)) {
42612 + /* prepare failed */
42613 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42615 + return HANDLER_ERROR;
42618 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42619 + CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"),
42620 + &(s->stmt_move_uri), &next_stmt)) {
42621 + /* prepare failed */
42622 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42624 + return HANDLER_ERROR;
42629 + if (SQLITE_OK != sqlite3_exec(s->sql,
42630 + "CREATE TABLE locks ("
42631 + " locktoken TEXT NOT NULL,"
42632 " resource TEXT NOT NULL,"
42633 - " prop TEXT NOT NULL,"
42634 - " ns TEXT NOT NULL,"
42635 - " value TEXT NOT NULL,"
42636 - " PRIMARY KEY(resource, prop, ns))",
42637 + " lockscope TEXT NOT NULL,"
42638 + " locktype TEXT NOT NULL,"
42639 + " owner TEXT NOT NULL,"
42640 + " depth INT NOT NULL,"
42641 + " timeout TIMESTAMP NOT NULL,"
42642 + " PRIMARY KEY(locktoken))",
42643 NULL, NULL, &err)) {
42645 - if (0 != strcmp(err, "table properties already exists")) {
42646 + if (0 != strcmp(err, "table locks already exists")) {
42647 log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
42650 @@ -228,127 +314,138 @@
42655 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42656 - CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"),
42657 - &(s->stmt_update_prop), &next_stmt)) {
42659 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42660 + CONST_STR_LEN("INSERT INTO locks (locktoken, resource, lockscope, locktype, owner, depth, timeout) VALUES (?,?,?,?,?,?, CURRENT_TIME + 600)"),
42661 + &(s->stmt_create_lock), &next_stmt)) {
42662 /* prepare failed */
42663 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42665 - log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
42666 return HANDLER_ERROR;
42669 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42670 - CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42671 - &(s->stmt_delete_prop), &next_stmt)) {
42672 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42673 + CONST_STR_LEN("DELETE FROM locks WHERE locktoken = ?"),
42674 + &(s->stmt_remove_lock), &next_stmt)) {
42675 /* prepare failed */
42676 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42678 return HANDLER_ERROR;
42681 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42682 - CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"),
42683 - &(s->stmt_delete_uri), &next_stmt)) {
42684 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42685 + CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE locktoken = ?"),
42686 + &(s->stmt_read_lock), &next_stmt)) {
42687 /* prepare failed */
42688 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42690 return HANDLER_ERROR;
42693 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42694 - CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"),
42695 - &(s->stmt_copy_uri), &next_stmt)) {
42696 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42697 + CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE resource = ?"),
42698 + &(s->stmt_read_lock_by_uri), &next_stmt)) {
42699 /* prepare failed */
42700 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42702 return HANDLER_ERROR;
42705 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42706 - CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"),
42707 - &(s->stmt_move_uri), &next_stmt)) {
42708 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42709 + CONST_STR_LEN("UPDATE locks SET timeout = CURRENT_TIME + 600 WHERE locktoken = ?"),
42710 + &(s->stmt_refresh_lock), &next_stmt)) {
42711 /* prepare failed */
42712 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42714 return HANDLER_ERROR;
42719 log_error_write(srv, __FILE__, __LINE__, "s", "Sorry, no sqlite3 and libxml2 support include, compile with --with-webdav-props");
42720 return HANDLER_ERROR;
42726 return HANDLER_GO_ON;
42729 -#define PATCH(x) \
42730 - p->conf.x = s->x;
42731 static int mod_webdav_patch_connection(server *srv, connection *con, plugin_data *p) {
42733 plugin_config *s = p->config_storage[0];
42736 - PATCH(is_readonly);
42740 + PATCH_OPTION(enabled);
42741 + PATCH_OPTION(is_readonly);
42742 + PATCH_OPTION(log_xml);
42744 #ifdef USE_PROPPATCH
42746 - PATCH(stmt_update_prop);
42747 - PATCH(stmt_delete_prop);
42748 - PATCH(stmt_select_prop);
42749 - PATCH(stmt_select_propnames);
42751 - PATCH(stmt_delete_uri);
42752 - PATCH(stmt_move_uri);
42753 - PATCH(stmt_copy_uri);
42754 + PATCH_OPTION(sql);
42755 + PATCH_OPTION(stmt_update_prop);
42756 + PATCH_OPTION(stmt_delete_prop);
42757 + PATCH_OPTION(stmt_select_prop);
42758 + PATCH_OPTION(stmt_select_propnames);
42760 + PATCH_OPTION(stmt_delete_uri);
42761 + PATCH_OPTION(stmt_move_uri);
42762 + PATCH_OPTION(stmt_copy_uri);
42764 + PATCH_OPTION(stmt_remove_lock);
42765 + PATCH_OPTION(stmt_refresh_lock);
42766 + PATCH_OPTION(stmt_create_lock);
42767 + PATCH_OPTION(stmt_read_lock);
42768 + PATCH_OPTION(stmt_read_lock_by_uri);
42770 /* skip the first, the global context */
42771 for (i = 1; i < srv->config_context->used; i++) {
42772 data_config *dc = (data_config *)srv->config_context->data[i];
42773 s = p->config_storage[i];
42776 /* condition didn't match */
42777 if (!config_check_cond(srv, con, dc)) continue;
42781 for (j = 0; j < dc->value->used; j++) {
42782 data_unset *du = dc->value->data[j];
42785 if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.activate"))) {
42787 + PATCH_OPTION(enabled);
42788 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.is-readonly"))) {
42789 - PATCH(is_readonly);
42790 + PATCH_OPTION(is_readonly);
42791 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.log-xml"))) {
42793 + PATCH_OPTION(log_xml);
42794 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.sqlite-db-name"))) {
42795 #ifdef USE_PROPPATCH
42797 - PATCH(stmt_update_prop);
42798 - PATCH(stmt_delete_prop);
42799 - PATCH(stmt_select_prop);
42800 - PATCH(stmt_select_propnames);
42802 - PATCH(stmt_delete_uri);
42803 - PATCH(stmt_move_uri);
42804 - PATCH(stmt_copy_uri);
42805 + PATCH_OPTION(sql);
42806 + PATCH_OPTION(stmt_update_prop);
42807 + PATCH_OPTION(stmt_delete_prop);
42808 + PATCH_OPTION(stmt_select_prop);
42809 + PATCH_OPTION(stmt_select_propnames);
42811 + PATCH_OPTION(stmt_delete_uri);
42812 + PATCH_OPTION(stmt_move_uri);
42813 + PATCH_OPTION(stmt_copy_uri);
42815 + PATCH_OPTION(stmt_remove_lock);
42816 + PATCH_OPTION(stmt_refresh_lock);
42817 + PATCH_OPTION(stmt_create_lock);
42818 + PATCH_OPTION(stmt_read_lock);
42819 + PATCH_OPTION(stmt_read_lock_by_uri);
42830 URIHANDLER_FUNC(mod_webdav_uri_handler) {
42831 plugin_data *p = p_d;
42836 if (con->uri.path->used == 0) return HANDLER_GO_ON;
42839 mod_webdav_patch_connection(srv, con, p);
42841 if (!p->conf.enabled) return HANDLER_GO_ON;
42842 @@ -362,20 +459,20 @@
42843 if (p->conf.is_readonly) {
42844 response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND"));
42846 - response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH"));
42847 + response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH, LOCK, UNLOCK"));
42856 return HANDLER_GO_ON;
42858 -static int webdav_gen_prop_tag(server *srv, connection *con,
42862 +static int webdav_gen_prop_tag(server *srv, connection *con,
42869 @@ -414,7 +511,7 @@
42870 buffer_append_string_buffer(b, dst->rel_path);
42871 buffer_append_string(b,"</D:href>\n");
42872 buffer_append_string(b,"<D:status>\n");
42875 if (con->request.http_version == HTTP_VERSION_1_1) {
42876 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
42878 @@ -458,14 +555,13 @@
42880 /* bind the values to the insert */
42882 - sqlite3_bind_text(stmt, 1,
42883 - dst->rel_path->ptr,
42884 + sqlite3_bind_text(stmt, 1,
42885 + dst->rel_path->ptr,
42886 dst->rel_path->used - 1,
42890 if (SQLITE_DONE != sqlite3_step(stmt)) {
42896 @@ -493,14 +589,14 @@
42897 (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
42899 /* ignore the parent dir */
42903 buffer_copy_string_buffer(d.path, dst->path);
42904 - BUFFER_APPEND_SLASH(d.path);
42905 + PATHNAME_APPEND_SLASH(d.path);
42906 buffer_append_string(d.path, de->d_name);
42909 buffer_copy_string_buffer(d.rel_path, dst->rel_path);
42910 - BUFFER_APPEND_SLASH(d.rel_path);
42911 + PATHNAME_APPEND_SLASH(d.rel_path);
42912 buffer_append_string(d.rel_path, de->d_name);
42914 /* stat and unlink afterwards */
42915 @@ -508,7 +604,7 @@
42916 /* don't about it yet, rmdir will fail too */
42917 } else if (S_ISDIR(st.st_mode)) {
42918 have_multi_status = webdav_delete_dir(srv, con, p, &d, b);
42921 /* try to unlink it */
42922 if (-1 == rmdir(d.path->ptr)) {
42924 @@ -535,14 +631,13 @@
42926 /* bind the values to the insert */
42928 - sqlite3_bind_text(stmt, 1,
42930 + sqlite3_bind_text(stmt, 1,
42932 d.rel_path->used - 1,
42936 if (SQLITE_DONE != sqlite3_step(stmt)) {
42942 @@ -569,7 +664,7 @@
42943 if (stream_open(&s, src->path)) {
42948 if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), 0600))) {
42949 /* opening the destination failed for some reason */
42951 @@ -601,7 +696,7 @@
42960 @@ -614,19 +709,18 @@
42961 sqlite3_reset(stmt);
42963 /* bind the values to the insert */
42964 - sqlite3_bind_text(stmt, 1,
42965 - dst->rel_path->ptr,
42966 + sqlite3_bind_text(stmt, 1,
42967 + dst->rel_path->ptr,
42968 dst->rel_path->used - 1,
42971 - sqlite3_bind_text(stmt, 2,
42972 - src->rel_path->ptr,
42973 + sqlite3_bind_text(stmt, 2,
42974 + src->rel_path->ptr,
42975 src->rel_path->used - 1,
42979 if (SQLITE_DONE != sqlite3_step(stmt)) {
42985 @@ -655,21 +749,21 @@
42986 (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
42991 buffer_copy_string_buffer(s.path, src->path);
42992 - BUFFER_APPEND_SLASH(s.path);
42993 + PATHNAME_APPEND_SLASH(s.path);
42994 buffer_append_string(s.path, de->d_name);
42996 buffer_copy_string_buffer(d.path, dst->path);
42997 - BUFFER_APPEND_SLASH(d.path);
42998 + PATHNAME_APPEND_SLASH(d.path);
42999 buffer_append_string(d.path, de->d_name);
43001 buffer_copy_string_buffer(s.rel_path, src->rel_path);
43002 - BUFFER_APPEND_SLASH(s.rel_path);
43003 + PATHNAME_APPEND_SLASH(s.rel_path);
43004 buffer_append_string(s.rel_path, de->d_name);
43006 buffer_copy_string_buffer(d.rel_path, dst->rel_path);
43007 - BUFFER_APPEND_SLASH(d.rel_path);
43008 + PATHNAME_APPEND_SLASH(d.rel_path);
43009 buffer_append_string(d.rel_path, de->d_name);
43011 if (-1 == stat(s.path->ptr, &st)) {
43012 @@ -692,19 +786,18 @@
43013 sqlite3_reset(stmt);
43015 /* bind the values to the insert */
43016 - sqlite3_bind_text(stmt, 1,
43017 - dst->rel_path->ptr,
43018 + sqlite3_bind_text(stmt, 1,
43019 + dst->rel_path->ptr,
43020 dst->rel_path->used - 1,
43023 - sqlite3_bind_text(stmt, 2,
43024 - src->rel_path->ptr,
43025 + sqlite3_bind_text(stmt, 2,
43026 + src->rel_path->ptr,
43027 src->rel_path->used - 1,
43031 if (SQLITE_DONE != sqlite3_step(stmt)) {
43037 @@ -721,7 +814,7 @@
43038 buffer_free(s.rel_path);
43039 buffer_free(d.path);
43040 buffer_free(d.rel_path);
43046 @@ -748,12 +841,12 @@
43047 if (S_ISDIR(sce->st.st_mode)) {
43048 buffer_append_string(b, "<D:getcontenttype>httpd/unix-directory</D:getcontenttype>");
43050 - } else if(S_ISREG(sce->st.st_mode)) {
43051 + } else if(S_ISREG(sce->st.st_mode)) {
43052 for (k = 0; k < con->conf.mimetypes->used; k++) {
43053 data_string *ds = (data_string *)con->conf.mimetypes->data[k];
43056 if (ds->key->used == 0) continue;
43059 if (buffer_is_equal_right_len(dst->path, ds->key, ds->key->used - 1)) {
43060 buffer_append_string(b,"<D:getcontenttype>");
43061 buffer_append_string_buffer(b, ds->value);
43062 @@ -807,23 +900,23 @@
43064 /* bind the values to the insert */
43066 - sqlite3_bind_text(stmt, 1,
43067 - dst->rel_path->ptr,
43068 + sqlite3_bind_text(stmt, 1,
43069 + dst->rel_path->ptr,
43070 dst->rel_path->used - 1,
43072 - sqlite3_bind_text(stmt, 2,
43073 + sqlite3_bind_text(stmt, 2,
43077 - sqlite3_bind_text(stmt, 3,
43078 + sqlite3_bind_text(stmt, 3,
43084 - while (SQLITE_ROW == sqlite3_step(p->conf.stmt_select_prop)) {
43085 + while (SQLITE_ROW == sqlite3_step(stmt)) {
43086 /* there is a row for us, we only expect a single col 'value' */
43087 - webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(p->conf.stmt_select_prop, 0), b);
43088 + webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(stmt, 0), b);
43092 @@ -840,7 +933,7 @@
43096 -webdav_property live_properties[] = {
43097 +webdav_property live_properties[] = {
43098 { "DAV:", "creationdate" },
43099 { "DAV:", "displayname" },
43100 { "DAV:", "getcontentlanguage" },
43101 @@ -871,8 +964,8 @@
43102 webdav_property *prop;
43104 prop = props->ptr[i];
43106 - if (0 != webdav_get_property(srv, con, p,
43108 + if (0 != webdav_get_property(srv, con, p,
43109 dst, prop->prop, prop->ns, b_200)) {
43110 webdav_gen_prop_tag(srv, con, prop->prop, prop->ns, NULL, b_404);
43112 @@ -916,12 +1009,12 @@
43113 if (-1 == c->file.fd && /* open the file if not already open */
43114 -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43115 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43122 if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43123 - log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
43124 + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
43125 strerror(errno), c->file.name, c->file.fd);
43128 @@ -938,7 +1031,7 @@
43129 if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->file.mmap.start + c->offset, weHave, 0))) {
43130 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
43134 c->offset += weHave;
43135 cq->bytes_out += weHave;
43137 @@ -956,7 +1049,7 @@
43138 if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->mem->ptr + c->offset, weHave, 0))) {
43139 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
43143 c->offset += weHave;
43144 cq->bytes_out += weHave;
43146 @@ -991,6 +1084,113 @@
43150 +int webdav_lockdiscovery(server *srv, connection *con,
43151 + buffer *locktoken, const char *lockscope, const char *locktype, int depth) {
43155 + response_header_overwrite(srv, con, CONST_STR_LEN("Lock-Token"), CONST_BUF_LEN(locktoken));
43157 + response_header_overwrite(srv, con,
43158 + CONST_STR_LEN("Content-Type"),
43159 + CONST_STR_LEN("text/xml; charset=\"utf-8\""));
43161 + b = chunkqueue_get_append_buffer(con->write_queue);
43163 + buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
43165 + buffer_append_string(b,"<D:prop xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
43166 + buffer_append_string(b,"<D:lockdiscovery>\n");
43167 + buffer_append_string(b,"<D:activelock>\n");
43169 + buffer_append_string(b,"<D:lockscope>");
43170 + buffer_append_string(b,"<D:");
43171 + buffer_append_string(b, lockscope);
43172 + buffer_append_string(b, "/>");
43173 + buffer_append_string(b,"</D:lockscope>\n");
43175 + buffer_append_string(b,"<D:locktype>");
43176 + buffer_append_string(b,"<D:");
43177 + buffer_append_string(b, locktype);
43178 + buffer_append_string(b, "/>");
43179 + buffer_append_string(b,"</D:locktype>\n");
43181 + buffer_append_string(b,"<D:depth>");
43182 + buffer_append_string(b, depth == 0 ? "0" : "infinity");
43183 + buffer_append_string(b,"</D:depth>\n");
43185 + buffer_append_string(b,"<D:timeout>");
43186 + buffer_append_string(b, "Second-600");
43187 + buffer_append_string(b,"</D:timeout>\n");
43189 + buffer_append_string(b,"<D:owner>");
43190 + buffer_append_string(b,"</D:owner>\n");
43192 + buffer_append_string(b,"<D:locktoken>");
43193 + buffer_append_string(b, "<D:href>");
43194 + buffer_append_string_buffer(b, locktoken);
43195 + buffer_append_string(b, "</D:href>");
43196 + buffer_append_string(b,"</D:locktoken>\n");
43198 + buffer_append_string(b,"</D:activelock>\n");
43199 + buffer_append_string(b,"</D:lockdiscovery>\n");
43200 + buffer_append_string(b,"</D:prop>\n");
43205 + * check if resource is having the right locks to access to resource
43210 +int webdav_has_lock(server *srv, connection *con, plugin_data *p, buffer *uri) {
43211 + int has_lock = 1;
43221 + * there is NOT, AND and OR
43222 + * and a list can be tagged
43224 + * (<lock-token>) is untagged
43225 + * <tag> (<lock-token>) is tagged
43227 + * as long as we don't handle collections it is simple. :)
43229 + * X-Litmus: locks: 11 (owner_modify)
43230 + * If: <http://127.0.0.1:1025/dav/litmus/lockme> (<opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1>)
43232 + * X-Litmus: locks: 16 (fail_cond_put)
43233 + * If: (<DAV:no-lock> ["-1622396671"])
43235 + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
43237 + /* we didn't provided a lock-token -> */
43238 + /* if the resource is locked -> 423 */
43240 + sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
43242 + sqlite3_reset(stmt);
43244 + sqlite3_bind_text(stmt, 1,
43245 + CONST_BUF_LEN(uri),
43246 + SQLITE_TRANSIENT);
43248 + while (SQLITE_ROW == sqlite3_step(stmt)) {
43257 URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
43258 plugin_data *p = p_d;
43260 @@ -1001,7 +1201,8 @@
43263 webdav_properties *req_props;
43265 + stat_cache_entry *sce = NULL;
43269 if (!p->conf.enabled) return HANDLER_GO_ON;
43270 @@ -1019,7 +1220,19 @@
43273 /* is there a content-body ? */
43276 + switch (stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
43277 + case HANDLER_ERROR:
43278 + if (errno == ENOENT) {
43279 + con->http_status = 404;
43280 + return HANDLER_FINISHED;
43288 #ifdef USE_PROPPATCH
43289 /* any special requests or just allprop ? */
43290 if (con->request.content_length) {
43291 @@ -1087,14 +1300,13 @@
43292 /* get all property names (EMPTY) */
43293 sqlite3_reset(stmt);
43294 /* bind the values to the insert */
43296 - sqlite3_bind_text(stmt, 1,
43297 - con->uri.path->ptr,
43299 + sqlite3_bind_text(stmt, 1,
43300 + con->uri.path->ptr,
43301 con->uri.path->used - 1,
43305 if (SQLITE_DONE != sqlite3_step(stmt)) {
43309 } else if (0 == xmlStrcmp(cmd->name, BAD_CAST "allprop")) {
43310 @@ -1115,13 +1327,13 @@
43311 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
43313 b = chunkqueue_get_append_buffer(con->write_queue);
43316 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
43318 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
43323 prop_200 = buffer_init();
43324 prop_404 = buffer_init();
43326 @@ -1129,7 +1341,7 @@
43329 webdav_get_props(srv, con, p, &(con->physical), req_props, prop_200, prop_404);
43332 buffer_append_string(b,"<D:response>\n");
43333 buffer_append_string(b,"<D:href>");
43334 buffer_append_string_buffer(b, con->uri.scheme);
43335 @@ -1145,9 +1357,9 @@
43336 buffer_append_string_buffer(b, prop_200);
43338 buffer_append_string(b,"</D:prop>\n");
43341 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
43344 buffer_append_string(b,"</D:propstat>\n");
43346 if (!buffer_is_empty(prop_404)) {
43347 @@ -1157,16 +1369,16 @@
43348 buffer_append_string_buffer(b, prop_404);
43350 buffer_append_string(b,"</D:prop>\n");
43353 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
43356 buffer_append_string(b,"</D:propstat>\n");
43359 buffer_append_string(b,"</D:response>\n");
43364 if (NULL != (dir = opendir(con->physical.path->ptr))) {
43367 @@ -1179,16 +1391,16 @@
43368 if (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0') {
43370 /* ignore the parent dir */
43374 buffer_copy_string_buffer(d.path, dst->path);
43375 - BUFFER_APPEND_SLASH(d.path);
43376 + PATHNAME_APPEND_SLASH(d.path);
43378 buffer_copy_string_buffer(d.rel_path, dst->rel_path);
43379 - BUFFER_APPEND_SLASH(d.rel_path);
43380 + PATHNAME_APPEND_SLASH(d.rel_path);
43382 if (de->d_name[0] == '.' && de->d_name[1] == '\0') {
43383 - /* don't append the . */
43384 + /* don't append the . */
43386 buffer_append_string(d.path, de->d_name);
43387 buffer_append_string(d.rel_path, de->d_name);
43388 @@ -1198,7 +1410,7 @@
43389 buffer_reset(prop_404);
43391 webdav_get_props(srv, con, p, &d, req_props, prop_200, prop_404);
43394 buffer_append_string(b,"<D:response>\n");
43395 buffer_append_string(b,"<D:href>");
43396 buffer_append_string_buffer(b, con->uri.scheme);
43397 @@ -1214,9 +1426,9 @@
43398 buffer_append_string_buffer(b, prop_200);
43400 buffer_append_string(b,"</D:prop>\n");
43403 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
43406 buffer_append_string(b,"</D:propstat>\n");
43408 if (!buffer_is_empty(prop_404)) {
43409 @@ -1226,9 +1438,9 @@
43410 buffer_append_string_buffer(b, prop_404);
43412 buffer_append_string(b,"</D:prop>\n");
43415 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
43418 buffer_append_string(b,"</D:propstat>\n");
43421 @@ -1275,7 +1487,7 @@
43423 return HANDLER_FINISHED;
43427 /* let's create the directory */
43429 if (-1 == mkdir(con->physical.path->ptr, 0700)) {
43430 @@ -1303,7 +1515,13 @@
43431 con->http_status = 403;
43432 return HANDLER_FINISHED;
43436 + /* does the client have a lock for this connection ? */
43437 + if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43438 + con->http_status = 423;
43439 + return HANDLER_FINISHED;
43442 /* stat and unlink afterwards */
43443 if (-1 == stat(con->physical.path->ptr, &st)) {
43444 /* don't about it yet, unlink will fail too */
43445 @@ -1323,7 +1541,7 @@
43446 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
43448 b = chunkqueue_get_append_buffer(con->write_queue);
43451 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
43453 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\">\n");
43454 @@ -1331,7 +1549,7 @@
43455 buffer_append_string_buffer(b, multi_status_resp);
43457 buffer_append_string(b,"</D:multistatus>\n");
43460 if (p->conf.log_xml) {
43461 log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
43463 @@ -1340,7 +1558,7 @@
43464 con->file_finished = 1;
43466 /* everything went fine, remove the directory */
43469 if (-1 == rmdir(con->physical.path->ptr)) {
43472 @@ -1375,97 +1593,174 @@
43473 case HTTP_METHOD_PUT: {
43475 chunkqueue *cq = con->request_content_queue;
43477 + data_string *ds_range;
43479 if (p->conf.is_readonly) {
43480 con->http_status = 403;
43481 return HANDLER_FINISHED;
43484 + /* is a exclusive lock set on the source */
43485 + if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43486 + con->http_status = 423;
43487 + return HANDLER_FINISHED;
43491 assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
43493 - /* taken what we have in the request-body and write it to a file */
43494 - if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC, 0600))) {
43495 - /* we can't open the file */
43496 - con->http_status = 403;
43499 + /* RFC2616 Section 9.6 PUT requires us to send 501 on all Content-* we don't support
43500 + * - most important Content-Range
43503 + * Example: Content-Range: bytes 100-1037/1038 */
43505 - con->http_status = 201; /* created */
43506 - con->file_finished = 1;
43507 + if (NULL != (ds_range = (data_string *)array_get_element(con->request.headers, "Content-Range"))) {
43508 + const char *num = ds_range->value->ptr;
43510 + char *err = NULL;
43512 - for (c = cq->first; c; c = cq->first) {
43514 + if (0 != strncmp(num, "bytes ", 6)) {
43515 + con->http_status = 501; /* not implemented */
43517 - /* copy all chunks */
43518 - switch(c->type) {
43521 - if (c->file.mmap.start == MAP_FAILED) {
43522 - if (-1 == c->file.fd && /* open the file if not already open */
43523 - -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43524 - log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43529 - if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43530 - log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
43531 - strerror(errno), c->file.name, c->file.fd);
43532 + return HANDLER_FINISHED;
43537 + /* we only support <num>- ... */
43539 - c->file.mmap.length = c->file.length;
43542 - close(c->file.fd);
43545 - /* chunk_reset() or chunk_free() will cleanup for us */
43548 - if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
43551 - con->http_status = 507;
43555 - con->http_status = 403;
43561 - if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
43564 - con->http_status = 507;
43568 - con->http_status = 403;
43573 + while (*num == ' ' || *num == '\t') num++;
43575 + if (*num == '\0') {
43576 + con->http_status = 501; /* not implemented */
43578 + return HANDLER_FINISHED;
43581 + offset = strtoll(num, &err, 10);
43583 + if (*err != '-' || offset < 0) {
43584 + con->http_status = 501; /* not implemented */
43586 + return HANDLER_FINISHED;
43589 + if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, 0600))) {
43592 + con->http_status = 404; /* not found */
43594 - case UNUSED_CHUNK:
43596 + con->http_status = 403; /* not found */
43599 + return HANDLER_FINISHED;
43602 + if (-1 == lseek(fd, offset, SEEK_SET)) {
43603 + con->http_status = 501; /* not implemented */
43607 + return HANDLER_FINISHED;
43609 + con->http_status = 200; /* modified */
43611 + /* take what we have in the request-body and write it to a file */
43613 + /* if the file doesn't exist, create it */
43614 + if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, 0600))) {
43615 + if (errno == ENOENT &&
43616 + -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0600))) {
43617 + /* we can't open the file */
43618 + con->http_status = 403;
43622 - cq->bytes_out += r;
43623 + return HANDLER_FINISHED;
43626 + con->http_status = 201; /* created */
43629 + con->http_status = 200; /* modified */
43633 + con->file_finished = 1;
43635 + for (c = cq->first; c; c = cq->first) {
43638 + /* copy all chunks */
43639 + switch(c->type) {
43642 + if (c->file.mmap.start == MAP_FAILED) {
43643 + if (-1 == c->file.fd && /* open the file if not already open */
43644 + -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43645 + log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43650 + if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43651 + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
43652 + strerror(errno), c->file.name, c->file.fd);
43657 + c->file.mmap.length = c->file.length;
43659 + close(c->file.fd);
43662 + /* chunk_reset() or chunk_free() will cleanup for us */
43665 + if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
43668 + con->http_status = 507;
43672 + con->http_status = 403;
43676 - chunkqueue_remove_finished_chunks(cq);
43679 + if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
43682 + con->http_status = 507;
43686 + con->http_status = 403;
43691 + case UNUSED_CHUNK:
43698 + cq->bytes_out += r;
43702 + chunkqueue_remove_finished_chunks(cq);
43706 return HANDLER_FINISHED;
43708 - case HTTP_METHOD_MOVE:
43709 + case HTTP_METHOD_MOVE:
43710 case HTTP_METHOD_COPY: {
43711 buffer *destination = NULL;
43713 @@ -1475,7 +1770,15 @@
43714 con->http_status = 403;
43715 return HANDLER_FINISHED;
43719 + /* is a exclusive lock set on the source */
43720 + if (con->request.http_method == HTTP_METHOD_MOVE) {
43721 + if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43722 + con->http_status = 423;
43723 + return HANDLER_FINISHED;
43727 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Destination"))) {
43728 destination = ds->value;
43730 @@ -1549,10 +1852,10 @@
43733 buffer_copy_string_buffer(p->physical.path, p->physical.doc_root);
43734 - BUFFER_APPEND_SLASH(p->physical.path);
43735 + PATHNAME_APPEND_SLASH(p->physical.path);
43736 buffer_copy_string_buffer(p->physical.basedir, p->physical.path);
43738 - /* don't add a second / */
43739 + /* don't add a second / */
43740 if (p->physical.rel_path->ptr[0] == '/') {
43741 buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr + 1, p->physical.rel_path->used - 2);
43743 @@ -1613,6 +1916,12 @@
43744 /* it is just a file, good */
43747 + /* does the client have a lock for this connection ? */
43748 + if (!webdav_has_lock(srv, con, p, p->uri.path)) {
43749 + con->http_status = 423;
43750 + return HANDLER_FINISHED;
43753 /* destination exists */
43754 if (0 == (r = stat(p->physical.path->ptr, &st))) {
43755 if (S_ISDIR(st.st_mode)) {
43756 @@ -1636,7 +1945,7 @@
43757 return HANDLER_FINISHED;
43759 } else if (overwrite == 0) {
43760 - /* destination exists, but overwrite is not set */
43761 + /* destination exists, but overwrite is not set */
43762 con->http_status = 412;
43763 return HANDLER_FINISHED;
43765 @@ -1655,16 +1964,16 @@
43766 sqlite3_reset(stmt);
43768 /* bind the values to the insert */
43769 - sqlite3_bind_text(stmt, 1,
43770 - p->uri.path->ptr,
43771 + sqlite3_bind_text(stmt, 1,
43772 + p->uri.path->ptr,
43773 p->uri.path->used - 1,
43776 - sqlite3_bind_text(stmt, 2,
43777 - con->uri.path->ptr,
43778 + sqlite3_bind_text(stmt, 2,
43779 + con->uri.path->ptr,
43780 con->uri.path->used - 1,
43784 if (SQLITE_DONE != sqlite3_step(stmt)) {
43785 log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move failed:", sqlite3_errmsg(p->conf.sql));
43787 @@ -1691,12 +2000,17 @@
43789 return HANDLER_FINISHED;
43791 - case HTTP_METHOD_PROPPATCH: {
43792 + case HTTP_METHOD_PROPPATCH:
43793 if (p->conf.is_readonly) {
43794 con->http_status = 403;
43795 return HANDLER_FINISHED;
43798 + if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43799 + con->http_status = 423;
43800 + return HANDLER_FINISHED;
43803 /* check if destination exists */
43804 if (-1 == stat(con->physical.path->ptr, &st)) {
43806 @@ -1737,7 +2051,7 @@
43808 sqlite3_stmt *stmt;
43810 - stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ?
43811 + stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ?
43812 p->conf.stmt_delete_prop : p->conf.stmt_update_prop;
43814 for (props = cmd->children; props; props = props->next) {
43815 @@ -1762,34 +2076,35 @@
43817 /* bind the values to the insert */
43819 - sqlite3_bind_text(stmt, 1,
43820 - con->uri.path->ptr,
43821 + sqlite3_bind_text(stmt, 1,
43822 + con->uri.path->ptr,
43823 con->uri.path->used - 1,
43825 - sqlite3_bind_text(stmt, 2,
43826 + sqlite3_bind_text(stmt, 2,
43827 (char *)prop->name,
43828 strlen((char *)prop->name),
43831 - sqlite3_bind_text(stmt, 3,
43832 + sqlite3_bind_text(stmt, 3,
43833 (char *)prop->ns->href,
43834 strlen((char *)prop->ns->href),
43837 - sqlite3_bind_text(stmt, 3,
43838 + sqlite3_bind_text(stmt, 3,
43843 if (stmt == p->conf.stmt_update_prop) {
43844 - sqlite3_bind_text(stmt, 4,
43845 + sqlite3_bind_text(stmt, 4,
43846 (char *)xmlNodeGetContent(prop),
43847 strlen((char *)xmlNodeGetContent(prop)),
43852 if (SQLITE_DONE != (r = sqlite3_step(stmt))) {
43853 - log_error_write(srv, __FILE__, __LINE__, "ss", "sql-set failed:", sqlite3_errmsg(p->conf.sql));
43854 + log_error_write(srv, __FILE__, __LINE__, "ss",
43855 + "sql-set failed:", sqlite3_errmsg(p->conf.sql));
43859 @@ -1804,7 +2119,7 @@
43861 goto propmatch_cleanup;
43865 con->http_status = 400;
43867 if (SQLITE_OK != sqlite3_exec(p->conf.sql, "COMMIT", NULL, NULL, &err)) {
43868 @@ -1821,6 +2136,7 @@
43875 con->http_status = 400;
43876 @@ -1830,11 +2146,307 @@
43878 con->http_status = 501;
43879 return HANDLER_FINISHED;
43881 + case HTTP_METHOD_LOCK:
43883 + * a mac wants to write
43885 + * LOCK /dav/expire.txt HTTP/1.1\r\n
43886 + * User-Agent: WebDAVFS/1.3 (01308000) Darwin/8.1.0 (Power Macintosh)\r\n
43887 + * Accept: * / *\r\n
43889 + * Timeout: Second-600\r\n
43890 + * Content-Type: text/xml; charset=\"utf-8\"\r\n
43891 + * Content-Length: 229\r\n
43892 + * Connection: keep-alive\r\n
43893 + * Host: 192.168.178.23:1025\r\n
43895 + * <?xml version=\"1.0\" encoding=\"utf-8\"?>\n
43896 + * <D:lockinfo xmlns:D=\"DAV:\">\n
43897 + * <D:lockscope><D:exclusive/></D:lockscope>\n
43898 + * <D:locktype><D:write/></D:locktype>\n
43900 + * <D:href>http://www.apple.com/webdav_fs/</D:href>\n
43902 + * </D:lockinfo>\n
43905 + if (depth != 0 && depth != -1) {
43906 + con->http_status = 400;
43908 + return HANDLER_FINISHED;
43912 + if (con->request.content_length) {
43914 + buffer *hdr_if = NULL;
43916 + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
43917 + hdr_if = ds->value;
43920 + /* we don't support Depth: Infinity on locks */
43921 + if (hdr_if == NULL && depth == -1) {
43922 + con->http_status = 409; /* Conflict */
43924 + return HANDLER_FINISHED;
43927 + if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
43928 + xmlNode *rootnode = xmlDocGetRootElement(xml);
43930 + assert(rootnode);
43932 + if (0 == xmlStrcmp(rootnode->name, BAD_CAST "lockinfo")) {
43933 + xmlNode *lockinfo;
43934 + const xmlChar *lockscope = NULL, *locktype = NULL, *owner = NULL;
43936 + for (lockinfo = rootnode->children; lockinfo; lockinfo = lockinfo->next) {
43937 + if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "lockscope")) {
43939 + for (value = lockinfo->children; value; value = value->next) {
43940 + if ((0 == xmlStrcmp(value->name, BAD_CAST "exclusive")) ||
43941 + (0 == xmlStrcmp(value->name, BAD_CAST "shared"))) {
43942 + lockscope = value->name;
43944 + con->http_status = 400;
43947 + return HANDLER_FINISHED;
43950 + } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "locktype")) {
43952 + for (value = lockinfo->children; value; value = value->next) {
43953 + if ((0 == xmlStrcmp(value->name, BAD_CAST "write"))) {
43954 + locktype = value->name;
43956 + con->http_status = 400;
43959 + return HANDLER_FINISHED;
43963 + } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "owner")) {
43967 + if (lockscope && locktype) {
43968 + sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
43970 + /* is this resourse already locked ? */
43972 + /* SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout
43974 + * WHERE resource = ? */
43978 + sqlite3_reset(stmt);
43980 + sqlite3_bind_text(stmt, 1,
43981 + p->uri.path->ptr,
43982 + p->uri.path->used - 1,
43983 + SQLITE_TRANSIENT);
43985 + /* it is the PK */
43986 + while (SQLITE_ROW == sqlite3_step(stmt)) {
43987 + /* we found a lock
43988 + * 1. is it compatible ?
43989 + * 2. is it ours */
43990 + char *sql_lockscope = (char *)sqlite3_column_text(stmt, 2);
43992 + if (strcmp(sql_lockscope, "exclusive")) {
43993 + con->http_status = 423;
43994 + } else if (0 == xmlStrcmp(lockscope, BAD_CAST "exclusive")) {
43995 + /* resourse is locked with a shared lock
43996 + * client wants exclusive */
43997 + con->http_status = 423;
44000 + if (con->http_status == 423) {
44002 + return HANDLER_FINISHED;
44006 + stmt = p->conf.stmt_create_lock;
44008 + /* create a lock-token */
44010 + char uuid[37] /* 36 + \0 */;
44012 + uuid_generate(id);
44013 + uuid_unparse(id, uuid);
44015 + buffer_copy_string(p->tmp_buf, "opaquelocktoken:");
44016 + buffer_append_string(p->tmp_buf, uuid);
44018 + /* "CREATE TABLE locks ("
44019 + * " locktoken TEXT NOT NULL,"
44020 + * " resource TEXT NOT NULL,"
44021 + * " lockscope TEXT NOT NULL,"
44022 + * " locktype TEXT NOT NULL,"
44023 + * " owner TEXT NOT NULL,"
44024 + * " depth INT NOT NULL,"
44027 + sqlite3_reset(stmt);
44029 + sqlite3_bind_text(stmt, 1,
44030 + CONST_BUF_LEN(p->tmp_buf),
44031 + SQLITE_TRANSIENT);
44033 + sqlite3_bind_text(stmt, 2,
44034 + CONST_BUF_LEN(con->uri.path),
44035 + SQLITE_TRANSIENT);
44037 + sqlite3_bind_text(stmt, 3,
44039 + xmlStrlen(lockscope),
44040 + SQLITE_TRANSIENT);
44042 + sqlite3_bind_text(stmt, 4,
44044 + xmlStrlen(locktype),
44045 + SQLITE_TRANSIENT);
44048 + sqlite3_bind_text(stmt, 5,
44051 + SQLITE_TRANSIENT);
44054 + sqlite3_bind_int(stmt, 6,
44058 + if (SQLITE_DONE != sqlite3_step(stmt)) {
44059 + log_error_write(srv, __FILE__, __LINE__, "ss",
44060 + "create lock:", sqlite3_errmsg(p->conf.sql));
44063 + /* looks like we survived */
44064 + webdav_lockdiscovery(srv, con, p->tmp_buf, lockscope, locktype, depth);
44066 + con->http_status = 201;
44067 + con->file_finished = 1;
44073 + return HANDLER_FINISHED;
44075 + con->http_status = 400;
44076 + return HANDLER_FINISHED;
44080 + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
44081 + buffer *locktoken = ds->value;
44082 + sqlite3_stmt *stmt = p->conf.stmt_refresh_lock;
44084 + /* remove the < > around the token */
44085 + if (locktoken->used < 6) {
44086 + con->http_status = 400;
44088 + return HANDLER_FINISHED;
44091 + buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 2, locktoken->used - 5);
44093 + sqlite3_reset(stmt);
44095 + sqlite3_bind_text(stmt, 1,
44096 + CONST_BUF_LEN(p->tmp_buf),
44097 + SQLITE_TRANSIENT);
44099 + if (SQLITE_DONE != sqlite3_step(stmt)) {
44100 + log_error_write(srv, __FILE__, __LINE__, "ss",
44101 + "refresh lock:", sqlite3_errmsg(p->conf.sql));
44104 + webdav_lockdiscovery(srv, con, p->tmp_buf, "exclusive", "write", 0);
44106 + con->http_status = 200;
44107 + con->file_finished = 1;
44108 + return HANDLER_FINISHED;
44110 + /* we need a lock-token to refresh */
44111 + con->http_status = 400;
44113 + return HANDLER_FINISHED;
44118 + con->http_status = 501;
44119 + return HANDLER_FINISHED;
44121 + case HTTP_METHOD_UNLOCK:
44123 + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Lock-Token"))) {
44124 + buffer *locktoken = ds->value;
44125 + sqlite3_stmt *stmt = p->conf.stmt_remove_lock;
44127 + /* remove the < > around the token */
44128 + if (locktoken->used < 4) {
44129 + con->http_status = 400;
44131 + return HANDLER_FINISHED;
44137 + * if the resourse is locked:
44138 + * - by us: unlock
44139 + * - by someone else: 401
44140 + * if the resource is not locked:
44144 + buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 1, locktoken->used - 3);
44146 + sqlite3_reset(stmt);
44148 + sqlite3_bind_text(stmt, 1,
44149 + CONST_BUF_LEN(p->tmp_buf),
44150 + SQLITE_TRANSIENT);
44152 + sqlite3_bind_text(stmt, 2,
44153 + CONST_BUF_LEN(con->uri.path),
44154 + SQLITE_TRANSIENT);
44156 + if (SQLITE_DONE != sqlite3_step(stmt)) {
44157 + log_error_write(srv, __FILE__, __LINE__, "ss",
44158 + "remove lock:", sqlite3_errmsg(p->conf.sql));
44161 + if (0 == sqlite3_changes(p->conf.sql)) {
44162 + con->http_status = 401;
44164 + con->http_status = 204;
44166 + return HANDLER_FINISHED;
44168 + /* we need a lock-token to unlock */
44169 + con->http_status = 400;
44171 + return HANDLER_FINISHED;
44175 + con->http_status = 501;
44176 + return HANDLER_FINISHED;
44184 return HANDLER_GO_ON;
44186 @@ -1845,14 +2457,14 @@
44187 int mod_webdav_plugin_init(plugin *p) {
44188 p->version = LIGHTTPD_VERSION_ID;
44189 p->name = buffer_init_string("webdav");
44192 p->init = mod_webdav_init;
44193 p->handle_uri_clean = mod_webdav_uri_handler;
44194 p->handle_physical = mod_webdav_subrequest_handler;
44195 p->set_defaults = mod_webdav_set_defaults;
44196 p->cleanup = mod_webdav_free;
44204 --- ../lighttpd-1.4.11/src/network.c 2006-03-04 16:45:46.000000000 +0200
44205 +++ lighttpd-1.4.12/src/network.c 2006-07-18 13:03:40.000000000 +0300
44207 #include <sys/types.h>
44208 #include <sys/stat.h>
44209 -#include <sys/time.h>
44213 -#include <unistd.h>
44214 #include <string.h>
44215 #include <stdlib.h>
44216 #include <assert.h>
44218 +#include <stdio.h>
44220 #include "network.h"
44221 #include "fdevent.h"
44223 @@ -19,11 +19,12 @@
44224 #include "network_backends.h"
44225 #include "sys-mmap.h"
44226 #include "sys-socket.h"
44227 +#include "sys-files.h"
44230 -# include <openssl/ssl.h>
44231 -# include <openssl/err.h>
44232 -# include <openssl/rand.h>
44233 +# include <openssl/ssl.h>
44234 +# include <openssl/err.h>
44235 +# include <openssl/rand.h>
44238 handler_t network_server_handle_fdevent(void *s, void *context, int revents) {
44239 @@ -31,25 +32,25 @@
44240 server_socket *srv_socket = (server_socket *)context;
44248 if (revents != FDEVENT_IN) {
44249 - log_error_write(srv, __FILE__, __LINE__, "sdd",
44250 + log_error_write(srv, __FILE__, __LINE__, "sdd",
44251 "strange event for server socket",
44253 + srv_socket->sock->fd,
44255 return HANDLER_ERROR;
44258 /* accept()s at most 100 connections directly
44260 - * we jump out after 100 to give the waiting connections a chance */
44261 + * we jump out after 100 to give the waiting connections a chance */
44262 for (loops = 0; loops < 100 && NULL != (con = connection_accept(srv, srv_socket)); loops++) {
44266 connection_state_machine(srv, con);
44269 switch(r = plugins_call_handle_joblist(srv, con)) {
44270 case HANDLER_FINISHED:
44271 case HANDLER_GO_ON:
44272 @@ -72,18 +73,18 @@
44274 int is_unix_domain_socket = 0;
44278 #ifdef SO_ACCEPTFILTER
44279 struct accept_filter_arg afa;
44284 WORD wVersionRequested;
44289 wVersionRequested = MAKEWORD( 2, 2 );
44292 err = WSAStartup( wVersionRequested, &wsaData );
44294 /* Tell the user that we could not find a usable */
44295 @@ -91,37 +92,37 @@
44301 srv_socket = calloc(1, sizeof(*srv_socket));
44302 - srv_socket->fd = -1;
44304 + srv_socket->sock = iosocket_init();
44306 srv_socket->srv_token = buffer_init();
44307 buffer_copy_string_buffer(srv_socket->srv_token, host_token);
44311 buffer_copy_string_buffer(b, host_token);
44318 if (NULL == (sp = strrchr(b->ptr, ':'))) {
44319 log_error_write(srv, __FILE__, __LINE__, "sb", "value of $SERVER[\"socket\"] has to be \"ip:port\".", b);
44329 /* check for [ and ] */
44330 if (b->ptr[0] == '[' && *(sp-1) == ']') {
44342 port = strtol(sp, NULL, 10);
44344 if (host[0] == '/') {
44345 @@ -129,18 +130,18 @@
44346 is_unix_domain_socket = 1;
44347 } else if (port == 0 || port > 65535) {
44348 log_error_write(srv, __FILE__, __LINE__, "sd", "port out of range:", port);
44355 if (*host == '\0') host = NULL;
44357 if (is_unix_domain_socket) {
44358 #ifdef HAVE_SYS_UN_H
44360 srv_socket->addr.plain.sa_family = AF_UNIX;
44362 - if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
44364 + if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
44365 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44368 @@ -154,32 +155,32 @@
44371 srv_socket->addr.plain.sa_family = AF_INET6;
44373 - if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44375 + if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44376 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44379 srv_socket->use_ipv6 = 1;
44383 - if (srv_socket->fd == -1) {
44385 + if (srv_socket->sock->fd == -1) {
44386 srv_socket->addr.plain.sa_family = AF_INET;
44387 - if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44388 + if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44389 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44396 - srv->cur_fds = srv_socket->fd;
44398 + srv->cur_fds = srv_socket->sock->fd;
44401 - if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
44402 + if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
44403 log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt failed:", strerror(errno));
44408 switch(srv_socket->addr.plain.sa_family) {
44411 @@ -190,23 +191,23 @@
44413 struct addrinfo hints, *res;
44417 memset(&hints, 0, sizeof(hints));
44420 hints.ai_family = AF_INET6;
44421 hints.ai_socktype = SOCK_STREAM;
44422 hints.ai_protocol = IPPROTO_TCP;
44425 if (0 != (r = getaddrinfo(host, NULL, &hints, &res))) {
44426 - log_error_write(srv, __FILE__, __LINE__,
44427 - "sssss", "getaddrinfo failed: ",
44428 + log_error_write(srv, __FILE__, __LINE__,
44429 + "sssss", "getaddrinfo failed: ",
44430 gai_strerror(r), "'", host, "'");
44437 memcpy(&(srv_socket->addr), res->ai_addr, res->ai_addrlen);
44442 srv_socket->addr.ipv6.sin6_port = htons(port);
44443 @@ -221,33 +222,34 @@
44445 struct hostent *he;
44446 if (NULL == (he = gethostbyname(host))) {
44447 - log_error_write(srv, __FILE__, __LINE__,
44448 - "sds", "gethostbyname failed: ",
44449 + log_error_write(srv, __FILE__, __LINE__,
44450 + "sds", "gethostbyname failed: ",
44456 if (he->h_addrtype != AF_INET) {
44457 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
44462 if (he->h_length != sizeof(struct in_addr)) {
44463 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
44468 memcpy(&(srv_socket->addr.ipv4.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
44470 srv_socket->addr.ipv4.sin_port = htons(port);
44473 addr_len = sizeof(struct sockaddr_in);
44479 srv_socket->addr.un.sun_family = AF_UNIX;
44480 strcpy(srv_socket->addr.un.sun_path, host);
44484 addr_len = SUN_LEN(&srv_socket->addr.un);
44486 @@ -256,11 +258,11 @@
44489 /* check if the socket exists and try to connect to it. */
44490 - if (-1 != (fd = connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
44491 + if (-1 != (fd = connect(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
44494 - log_error_write(srv, __FILE__, __LINE__, "ss",
44495 - "server socket is still in use:",
44496 + log_error_write(srv, __FILE__, __LINE__, "ss",
44497 + "server socket is still in use:",
44501 @@ -275,88 +277,89 @@
44505 - log_error_write(srv, __FILE__, __LINE__, "sds",
44506 - "testing socket failed:",
44507 + log_error_write(srv, __FILE__, __LINE__, "sds",
44508 + "testing socket failed:",
44509 host, strerror(errno));
44523 - if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
44525 + if (0 != bind(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
44526 switch(srv_socket->addr.plain.sa_family) {
44528 - log_error_write(srv, __FILE__, __LINE__, "sds",
44529 - "can't bind to socket:",
44530 + log_error_write(srv, __FILE__, __LINE__, "sds",
44531 + "can't bind to socket:",
44532 host, strerror(errno));
44535 - log_error_write(srv, __FILE__, __LINE__, "ssds",
44536 - "can't bind to port:",
44537 + log_error_write(srv, __FILE__, __LINE__, "ssds",
44538 + "can't bind to port:",
44539 host, port, strerror(errno));
44545 - if (-1 == listen(srv_socket->fd, 128 * 8)) {
44547 + if (-1 == listen(srv_socket->sock->fd, 128 * 8)) {
44548 log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));
44555 if (srv->ssl_is_init == 0) {
44556 SSL_load_error_strings();
44557 SSL_library_init();
44558 srv->ssl_is_init = 1;
44561 if (0 == RAND_status()) {
44562 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44563 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44564 "not enough entropy in the pool");
44570 if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
44571 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44572 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44573 ERR_error_string(ERR_get_error(), NULL));
44578 if (buffer_is_empty(s->ssl_pemfile)) {
44579 log_error_write(srv, __FILE__, __LINE__, "s", "ssl.pemfile has to be set");
44584 if (!buffer_is_empty(s->ssl_ca_file)) {
44585 if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {
44586 - log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44587 + log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44588 ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
44594 if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
44595 - log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44596 + log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44597 ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
44602 if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
44603 - log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44604 + log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44605 ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
44610 if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
44611 - log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
44612 + log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
44613 "Private key does not match the certificate public key, reason:",
44614 ERR_error_string(ERR_get_error(), NULL),
44616 @@ -364,15 +367,15 @@
44618 srv_socket->ssl_ctx = s->ssl_ctx;
44622 buffer_free(srv_socket->srv_token);
44628 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44630 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44631 "ssl requested but openssl support is not compiled in");
44637 @@ -383,17 +386,16 @@
44639 memset(&afa, 0, sizeof(afa));
44640 strcpy(afa.af_name, "httpready");
44641 - if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
44642 + if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
44643 if (errno != ENOENT) {
44644 log_error_write(srv, __FILE__, __LINE__, "ss", "can't set accept-filter 'httpready': ", strerror(errno));
44651 srv_socket->is_ssl = s->is_ssl;
44652 - srv_socket->fde_ndx = -1;
44655 if (srv->srv_sockets.size == 0) {
44656 srv->srv_sockets.size = 4;
44657 srv->srv_sockets.used = 0;
44658 @@ -402,11 +404,10 @@
44659 srv->srv_sockets.size += 4;
44660 srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket));
44664 srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
44672 @@ -414,45 +415,60 @@
44674 for (i = 0; i < srv->srv_sockets.used; i++) {
44675 server_socket *srv_socket = srv->srv_sockets.ptr[i];
44677 - if (srv_socket->fd != -1) {
44679 + if (srv_socket->sock->fd != -1) {
44680 /* check if server fd are already registered */
44681 - if (srv_socket->fde_ndx != -1) {
44682 - fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
44683 - fdevent_unregister(srv->ev, srv_socket->fd);
44684 + if (srv_socket->sock->fde_ndx != -1) {
44685 + fdevent_event_del(srv->ev, srv_socket->sock);
44686 + fdevent_unregister(srv->ev, srv_socket->sock);
44689 - close(srv_socket->fd);
44691 + closesocket(srv_socket->sock->fd);
44694 + if (srv_socket->is_ssl) {
44695 +#ifdef USE_OPENSSL
44696 + SSL_CTX_free(srv_socket->ssl_ctx);
44701 + iosocket_free(srv_socket->sock);
44703 buffer_free(srv_socket->srv_token);
44710 +#ifdef USE_OPENSSL
44711 + ERR_free_strings();
44713 free(srv->srv_sockets.ptr);
44720 NETWORK_BACKEND_UNSET,
44722 NETWORK_BACKEND_WRITE,
44723 NETWORK_BACKEND_WRITEV,
44724 NETWORK_BACKEND_LINUX_SENDFILE,
44725 NETWORK_BACKEND_FREEBSD_SENDFILE,
44726 - NETWORK_BACKEND_SOLARIS_SENDFILEV
44727 + NETWORK_BACKEND_SOLARIS_SENDFILEV,
44729 + NETWORK_BACKEND_WIN32_SEND,
44730 + NETWORK_BACKEND_WIN32_TRANSMITFILE,
44731 } network_backend_t;
44733 int network_init(server *srv) {
44736 network_backend_t backend;
44739 - network_backend_t nb;
44740 - const char *name;
44741 - } network_backends[] = {
44744 + network_backend_t nb;
44745 + const char *name;
44746 + } network_backends[] = {
44747 /* lowest id wins */
44748 #if defined USE_LINUX_SENDFILE
44749 { NETWORK_BACKEND_LINUX_SENDFILE, "linux-sendfile" },
44750 @@ -466,21 +482,30 @@
44751 #if defined USE_WRITEV
44752 { NETWORK_BACKEND_WRITEV, "writev" },
44754 +#if defined USE_WRITE
44755 { NETWORK_BACKEND_WRITE, "write" },
44757 +#if defined USE_WIN32_TRANSMITFILE
44758 + { NETWORK_BACKEND_WIN32_TRANSMITFILE, "win32-transmitfile" },
44760 +#if defined USE_WIN32_SEND
44761 + { NETWORK_BACKEND_WIN32_SEND, "win32-send" },
44764 { NETWORK_BACKEND_UNSET, NULL }
44771 buffer_copy_string_buffer(b, srv->srvconf.bindhost);
44772 buffer_append_string(b, ":");
44773 buffer_append_long(b, srv->srvconf.port);
44776 if (0 != network_server_init(srv, b, srv->config_storage[0])) {
44783 srv->network_ssl_backend_write = network_write_chunkqueue_openssl;
44785 @@ -500,54 +525,80 @@
44786 if (NULL == network_backends[i].name) {
44787 /* we don't know it */
44789 - log_error_write(srv, __FILE__, __LINE__, "sb",
44790 - "server.network-backend has a unknown value:",
44791 + log_error_write(srv, __FILE__, __LINE__, "sb",
44792 + "server.network-backend has a unknown value:",
44793 srv->srvconf.network_backend);
44799 +#define SET_NETWORK_BACKEND(read, write) \
44800 + srv->network_backend_write = network_write_chunkqueue_##write;\
44801 + srv->network_backend_read = network_read_chunkqueue_##read
44803 +#define SET_NETWORK_BACKEND_SSL(read, write) \
44804 + srv->network_ssl_backend_write = network_write_chunkqueue_##write;\
44805 + srv->network_ssl_backend_read = network_read_chunkqueue_##read
44809 +#ifdef USE_WIN32_SEND
44810 + case NETWORK_BACKEND_WIN32_SEND:
44811 + SET_NETWORK_BACKEND(win32recv, win32send);
44813 +#ifdef USE_WIN32_TRANSMITFILE
44814 + case NETWORK_BACKEND_WIN32_TRANSMITFILE:
44815 + SET_NETWORK_BACKEND(win32recv, win32transmitfile);
44821 case NETWORK_BACKEND_WRITE:
44822 - srv->network_backend_write = network_write_chunkqueue_write;
44823 + SET_NETWORK_BACKEND(read, write);
44827 case NETWORK_BACKEND_WRITEV:
44828 - srv->network_backend_write = network_write_chunkqueue_writev;
44829 + SET_NETWORK_BACKEND(read, writev);
44832 #ifdef USE_LINUX_SENDFILE
44833 case NETWORK_BACKEND_LINUX_SENDFILE:
44834 - srv->network_backend_write = network_write_chunkqueue_linuxsendfile;
44835 + SET_NETWORK_BACKEND(read, linuxsendfile);
44838 #ifdef USE_FREEBSD_SENDFILE
44839 case NETWORK_BACKEND_FREEBSD_SENDFILE:
44840 - srv->network_backend_write = network_write_chunkqueue_freebsdsendfile;
44841 + SET_NETWORK_BACKEND(read, freebsdsendfile);
44844 #ifdef USE_SOLARIS_SENDFILEV
44845 case NETWORK_BACKEND_SOLARIS_SENDFILEV:
44846 - srv->network_backend_write = network_write_chunkqueue_solarissendfilev;
44847 + SET_NETWORK_BACKEND(read, solarissendfilev);
44854 +#ifdef USE_OPENSSL
44855 + SET_NETWORK_BACKEND_SSL(openssl, openssl);
44858 /* check for $SERVER["socket"] */
44859 for (i = 1; i < srv->config_context->used; i++) {
44860 data_config *dc = (data_config *)srv->config_context->data[i];
44861 specific_config *s = srv->config_storage[i];
44865 /* not our stage */
44866 if (COMP_SERVER_SOCKET != dc->comp) continue;
44869 if (dc->cond != CONFIG_COND_EQ) {
44870 log_error_write(srv, __FILE__, __LINE__, "s", "only == is allowed for $SERVER[\"socket\"].");
44876 @@ -558,36 +609,47 @@
44882 if (j == srv->srv_sockets.used) {
44883 if (0 != network_server_init(srv, dc->string, s)) return -1;
44891 int network_register_fdevents(server *srv) {
44894 if (-1 == fdevent_reset(srv->ev)) {
44898 /* register fdevents after reset */
44899 for (i = 0; i < srv->srv_sockets.used; i++) {
44900 server_socket *srv_socket = srv->srv_sockets.ptr[i];
44902 - fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
44903 - fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
44904 + fdevent_register(srv->ev, srv_socket->sock, network_server_handle_fdevent, srv_socket);
44905 + fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
44910 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
44912 +network_status_t network_read_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
44913 + server_socket *srv_socket = con->srv_socket;
44915 + if (srv_socket->is_ssl) {
44916 +#ifdef USE_OPENSSL
44917 + return srv->network_ssl_backend_read(srv, con, con->sock, cq);
44919 + return NETWORK_STATUS_FATAL_ERROR;
44922 + return srv->network_backend_read(srv, con, con->sock, cq);
44926 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
44927 + network_status_t ret = NETWORK_STATUS_UNSET;
44933 server_socket *srv_socket = con->srv_socket;
44934 @@ -600,37 +662,42 @@
44935 joblist_append(srv, con);
44941 written = cq->bytes_out;
44945 /* Linux: put a cork into the socket as we want to combine the write() calls
44946 * but only if we really have multiple chunks
44948 if (cq->first && cq->first->next) {
44950 - setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
44951 + setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
44956 if (srv_socket->is_ssl) {
44958 - ret = srv->network_ssl_backend_write(srv, con, con->ssl, cq);
44959 + ret = srv->network_ssl_backend_write(srv, con, con->sock, cq);
44962 - ret = srv->network_backend_write(srv, con, con->fd, cq);
44963 + ret = srv->network_backend_write(srv, con, con->sock, cq);
44969 + case NETWORK_STATUS_WAIT_FOR_EVENT:
44970 + case NETWORK_STATUS_SUCCESS:
44971 chunkqueue_remove_finished_chunks(cq);
44972 - ret = chunkqueue_is_empty(cq) ? 0 : 1;
44983 - setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
44984 + setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
44988 @@ -639,13 +706,13 @@
44989 con->bytes_written_cur_second += written;
44991 *(con->conf.global_bytes_per_second_cnt_ptr) += written;
44994 if (con->conf.kbytes_per_second &&
44995 (con->bytes_written_cur_second > con->conf.kbytes_per_second * 1024)) {
44996 /* we reached the traffic limit */
44998 con->traffic_limit_reached = 1;
44999 joblist_append(srv, con);
45004 --- ../lighttpd-1.4.11/src/network.h 2005-08-11 01:26:42.000000000 +0300
45005 +++ lighttpd-1.4.12/src/network.h 2006-07-18 13:03:40.000000000 +0300
45008 #include "server.h"
45010 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
45011 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
45012 +network_status_t network_read_chunkqueue(server *srv, connection *con, chunkqueue *c);
45014 int network_init(server *srv);
45015 int network_close(server *srv);
45017 int network_register_fdevents(server *srv);
45018 +handler_t network_server_handle_fdevent(void *s, void *context, int revents);
45021 --- ../lighttpd-1.4.11/src/network_backends.h 2005-10-24 15:13:51.000000000 +0300
45022 +++ lighttpd-1.4.12/src/network_backends.h 2006-07-18 13:03:40.000000000 +0300
45023 @@ -43,16 +43,47 @@
45024 # define USE_AIX_SENDFILE
45028 +* unix can use read/write or recv/send on sockets
45029 +* win32 only recv/send
45032 +# define USE_WIN32_SEND
45033 +/* wait for async-io support
45034 +# define USE_WIN32_TRANSMITFILE
45037 +# define USE_WRITE
45041 +#include "network.h"
45043 +#define NETWORK_BACKEND_WRITE_CHUNK(x) \
45044 + network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq, chunk *c)
45046 +#define NETWORK_BACKEND_WRITE(x) \
45047 + network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
45048 +#define NETWORK_BACKEND_READ(x) \
45049 + network_status_t network_read_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
45051 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem);
45053 +NETWORK_BACKEND_WRITE(write);
45054 +NETWORK_BACKEND_WRITE(writev);
45055 +NETWORK_BACKEND_WRITE(linuxsendfile);
45056 +NETWORK_BACKEND_WRITE(freebsdsendfile);
45057 +NETWORK_BACKEND_WRITE(solarissendfilev);
45059 +NETWORK_BACKEND_WRITE(win32transmitfile);
45060 +NETWORK_BACKEND_WRITE(win32send);
45062 +NETWORK_BACKEND_READ(read);
45063 +NETWORK_BACKEND_READ(win32recv);
45065 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq);
45066 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq);
45067 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
45068 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
45069 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq);
45071 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq);
45072 +NETWORK_BACKEND_WRITE(openssl);
45073 +NETWORK_BACKEND_READ(openssl);
45077 --- ../lighttpd-1.4.11/src/network_freebsd_sendfile.c 2005-10-22 12:28:18.000000000 +0300
45078 +++ lighttpd-1.4.12/src/network_freebsd_sendfile.c 2006-07-16 00:26:04.000000000 +0300
45079 @@ -26,142 +26,61 @@
45082 # ifdef __FreeBSD__
45083 -/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
45084 +/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
45085 # define UIO_MAXIOV 1024
45089 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
45090 +NETWORK_BACKEND_WRITE(freebsdsendfile) {
45092 size_t chunks_written = 0;
45095 for(c = cq->first; c; c = c->next, chunks_written++) {
45096 int chunk_finished = 0;
45098 + network_status_t ret;
45101 - case MEM_CHUNK: {
45106 - size_t num_chunks, i;
45107 - struct iovec chunks[UIO_MAXIOV];
45109 - size_t num_bytes = 0;
45111 - /* we can't send more then SSIZE_MAX bytes in one chunk */
45113 - /* build writev list
45115 - * 1. limit: num_chunks < UIO_MAXIOV
45116 - * 2. limit: num_bytes < SSIZE_MAX
45118 - for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
45120 - for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
45121 - if (tc->mem->used == 0) {
45122 - chunks[i].iov_base = tc->mem->ptr;
45123 - chunks[i].iov_len = 0;
45125 - offset = tc->mem->ptr + tc->offset;
45126 - toSend = tc->mem->used - 1 - tc->offset;
45128 - chunks[i].iov_base = offset;
45130 - /* protect the return value of writev() */
45131 - if (toSend > SSIZE_MAX ||
45132 - num_bytes + toSend > SSIZE_MAX) {
45133 - chunks[i].iov_len = SSIZE_MAX - num_bytes;
45135 - num_chunks = i + 1;
45138 - chunks[i].iov_len = toSend;
45141 - num_bytes += toSend;
45145 - if ((r = writev(fd, chunks, num_chunks)) < 0) {
45155 - log_error_write(srv, __FILE__, __LINE__, "ssd",
45156 - "writev failed:", strerror(errno), fd);
45161 + ret = network_write_chunkqueue_writev_mem(srv, con, fd, cq, &c);
45166 - /* check which chunks have been written */
45167 - cq->bytes_out += r;
45169 - for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
45170 - if (r >= (ssize_t)chunks[i].iov_len) {
45172 - r -= chunks[i].iov_len;
45173 - tc->offset += chunks[i].iov_len;
45175 - if (chunk_finished) {
45176 - /* skip the chunks from further touches */
45177 - chunks_written++;
45180 - /* chunks_written + c = c->next is done in the for()*/
45181 - chunk_finished++;
45184 - /* partially written */
45187 - chunk_finished = 0;
45191 + if (ret != NETWORK_STATUS_SUCCESS) {
45196 + chunk_finished = 1;
45203 stat_cache_entry *sce = NULL;
45207 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45208 log_error_write(srv, __FILE__, __LINE__, "sb",
45209 strerror(errno), c->file.name);
45211 + return NETWORK_STATUS_FATAL_ERROR;
45215 offset = c->file.start + c->offset;
45216 /* limit the toSend to 2^31-1 bytes in a chunk */
45217 - toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
45218 + toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
45219 ((1 << 30) - 1) : c->file.length - c->offset;
45222 if (offset > sce->st.st_size) {
45223 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
45227 + return NETWORK_STATUS_FATAL_ERROR;
45231 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
45232 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
45236 + return NETWORK_STATUS_FATAL_ERROR;
45243 /* FreeBSD sendfile() */
45244 if (-1 == sendfile(ifd, fd, offset, toSend, NULL, &r, 0)) {
45246 @@ -169,39 +88,39 @@
45251 + return NETWORK_STATUS_CONNECTION_CLOSE;
45253 log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
45256 + return NETWORK_STATUS_FATAL_ERROR;
45263 cq->bytes_out += r;
45266 if (c->offset == c->file.length) {
45267 chunk_finished = 1;
45276 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
45283 if (!chunk_finished) {
45284 /* not finished yet */
45291 - return chunks_written;
45292 + return NETWORK_STATUS_SUCCESS;
45296 --- ../lighttpd-1.4.11/src/network_linux_sendfile.c 2006-02-15 20:02:36.000000000 +0200
45297 +++ lighttpd-1.4.12/src/network_linux_sendfile.c 2006-07-18 13:03:40.000000000 +0300
45298 @@ -26,122 +26,54 @@
45299 /* on linux 2.4.29 + debian/ubuntu we have crashes if this is enabled */
45300 #undef HAVE_POSIX_FADVISE
45302 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
45304 +NETWORK_BACKEND_WRITE(linuxsendfile) {
45306 size_t chunks_written = 0;
45309 for(c = cq->first; c; c = c->next, chunks_written++) {
45310 int chunk_finished = 0;
45312 + network_status_t ret;
45315 - case MEM_CHUNK: {
45320 - size_t num_chunks, i;
45321 - struct iovec chunks[UIO_MAXIOV];
45323 - size_t num_bytes = 0;
45325 - /* we can't send more then SSIZE_MAX bytes in one chunk */
45327 - /* build writev list
45329 - * 1. limit: num_chunks < UIO_MAXIOV
45330 - * 2. limit: num_bytes < SSIZE_MAX
45332 - for (num_chunks = 0, tc = c;
45333 - tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV;
45334 - tc = tc->next, num_chunks++);
45336 - for (tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
45337 - if (tc->mem->used == 0) {
45338 - chunks[i].iov_base = tc->mem->ptr;
45339 - chunks[i].iov_len = 0;
45341 - offset = tc->mem->ptr + tc->offset;
45342 - toSend = tc->mem->used - 1 - tc->offset;
45344 - chunks[i].iov_base = offset;
45346 - /* protect the return value of writev() */
45347 - if (toSend > SSIZE_MAX ||
45348 - num_bytes + toSend > SSIZE_MAX) {
45349 - chunks[i].iov_len = SSIZE_MAX - num_bytes;
45351 - num_chunks = i + 1;
45354 - chunks[i].iov_len = toSend;
45357 - num_bytes += toSend;
45361 - if ((r = writev(fd, chunks, num_chunks)) < 0) {
45371 - log_error_write(srv, __FILE__, __LINE__, "ssd",
45372 - "writev failed:", strerror(errno), fd);
45378 - /* check which chunks have been written */
45379 - cq->bytes_out += r;
45381 + ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
45383 - for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
45384 - if (r >= (ssize_t)chunks[i].iov_len) {
45386 - r -= chunks[i].iov_len;
45387 - tc->offset += chunks[i].iov_len;
45389 + /* check which chunks are finished now */
45390 + for (tc = c; tc; tc = tc->next) {
45391 + /* finished the chunk */
45392 + if (tc->offset == tc->mem->used - 1) {
45393 + /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
45394 if (chunk_finished) {
45395 - /* skip the chunks from further touches */
45396 - chunks_written++;
45399 - /* chunks_written + c = c->next is done in the for()*/
45400 - chunk_finished++;
45401 + chunk_finished = 1;
45404 - /* partially written */
45407 - chunk_finished = 0;
45414 + if (ret != NETWORK_STATUS_SUCCESS) {
45424 stat_cache_entry *sce = NULL;
45427 offset = c->file.start + c->offset;
45428 /* limit the toSend to 2^31-1 bytes in a chunk */
45429 - toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
45430 + toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
45431 ((1 << 30) - 1) : c->file.length - c->offset;
45433 - /* open file if not already opened */
45435 + /* open file if not already opened */
45436 if (-1 == c->file.fd) {
45437 if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
45438 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
45444 @@ -151,14 +83,14 @@
45445 /* tell the kernel that we want to stream the file */
45446 if (-1 == posix_fadvise(c->file.fd, 0, 0, POSIX_FADV_SEQUENTIAL)) {
45447 if (ENOSYS != errno) {
45448 - log_error_write(srv, __FILE__, __LINE__, "ssd",
45449 + log_error_write(srv, __FILE__, __LINE__, "ssd",
45450 "posix_fadvise failed:", strerror(errno), c->file.fd);
45456 - if (-1 == (r = sendfile(fd, c->file.fd, &offset, toSend))) {
45457 + if (-1 == (r = sendfile(sock->fd, c->file.fd, &offset, toSend))) {
45461 @@ -166,11 +98,11 @@
45466 + return NETWORK_STATUS_CONNECTION_CLOSE;
45468 - log_error_write(srv, __FILE__, __LINE__, "ssd",
45469 - "sendfile failed:", strerror(errno), fd);
45471 + log_error_write(srv, __FILE__, __LINE__, "ssd",
45472 + "sendfile failed:", strerror(errno), sock->fd);
45473 + return NETWORK_STATUS_FATAL_ERROR;
45477 @@ -179,39 +111,39 @@
45479 * - the file shrinked -> error
45480 * - the remote side closed inbetween -> remote-close */
45483 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45484 /* file is gone ? */
45486 + return NETWORK_STATUS_FATAL_ERROR;
45489 if (offset > sce->st.st_size) {
45490 /* file shrinked, close the connection */
45492 + return NETWORK_STATUS_FATAL_ERROR;
45496 + return NETWORK_STATUS_CONNECTION_CLOSE;
45499 #ifdef HAVE_POSIX_FADVISE
45502 -#define M * 1024 K
45503 +#define M * 1024 K
45504 #define READ_AHEAD 4 M
45505 /* check if we need a new chunk */
45506 if ((c->offset & ~(READ_AHEAD - 1)) != ((c->offset + r) & ~(READ_AHEAD - 1))) {
45507 /* tell the kernel that we want to stream the file */
45508 if (-1 == posix_fadvise(c->file.fd, (c->offset + r) & ~(READ_AHEAD - 1), READ_AHEAD, POSIX_FADV_NOREUSE)) {
45509 - log_error_write(srv, __FILE__, __LINE__, "ssd",
45510 + log_error_write(srv, __FILE__, __LINE__, "ssd",
45511 "posix_fadvise failed:", strerror(errno), c->file.fd);
45519 cq->bytes_out += r;
45522 if (c->offset == c->file.length) {
45523 chunk_finished = 1;
45525 @@ -222,24 +154,24 @@
45536 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
45540 + return NETWORK_STATUS_FATAL_ERROR;
45544 if (!chunk_finished) {
45545 /* not finished yet */
45549 + return NETWORK_STATUS_WAIT_FOR_EVENT;
45553 - return chunks_written;
45554 + return NETWORK_STATUS_SUCCESS;
45558 --- ../lighttpd-1.4.11/src/network_openssl.c 2005-11-17 14:53:29.000000000 +0200
45559 +++ lighttpd-1.4.12/src/network_openssl.c 2006-07-18 13:03:40.000000000 +0300
45560 @@ -23,17 +23,87 @@
45562 #include "stat_cache.h"
45564 -# include <openssl/ssl.h>
45565 -# include <openssl/err.h>
45566 +# include <openssl/ssl.h>
45567 +# include <openssl/err.h>
45569 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq) {
45570 +NETWORK_BACKEND_READ(openssl) {
45574 + b = chunkqueue_get_append_buffer(cq);
45575 + buffer_prepare_copy(b, 8192);
45576 + len = SSL_read(sock->ssl, b->ptr, b->size - 1);
45578 + log_error_write(srv, __FILE__, __LINE__, "so", "SSL:", len);
45583 + switch ((r = SSL_get_error(sock->ssl, len))) {
45584 + case SSL_ERROR_WANT_READ:
45585 + return NETWORK_STATUS_WAIT_FOR_EVENT;
45586 + case SSL_ERROR_SYSCALL:
45588 + * man SSL_get_error()
45590 + * SSL_ERROR_SYSCALL
45591 + * Some I/O error occurred. The OpenSSL error queue may contain more
45592 + * information on the error. If the error queue is empty (i.e.
45593 + * ERR_get_error() returns 0), ret can be used to find out more about
45594 + * the error: If ret == 0, an EOF was observed that violates the
45595 + * protocol. If ret == -1, the underlying BIO reported an I/O error
45596 + * (for socket I/O on Unix systems, consult errno for details).
45599 + while((ssl_err = ERR_get_error())) {
45600 + /* get all errors from the error-queue */
45601 + log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
45602 + r, ERR_error_string(ssl_err, NULL));
45607 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45609 + strerror(errno));
45614 + case SSL_ERROR_ZERO_RETURN:
45615 + /* clean shutdown on the remote side */
45618 + /* FIXME: later */
45621 + /* fall thourgh */
45623 + while((ssl_err = ERR_get_error())) {
45624 + /* get all errors from the error-queue */
45625 + log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
45626 + r, ERR_error_string(ssl_err, NULL));
45634 + b->ptr[b->used - 1] = '\0';
45636 + return NETWORK_STATUS_SUCCESS;
45640 +NETWORK_BACKEND_WRITE(openssl) {
45643 size_t chunks_written = 0;
45645 /* this is a 64k sendbuffer
45647 - * it has to stay at the same location all the time to satisfy the needs
45648 + * it has to stay at the same location all the time to satisfy the needs
45649 * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
45651 * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
45652 @@ -43,59 +113,61 @@
45653 * In reality we would like to use mmap() but we don't have a guarantee that
45654 * we get the same mmap() address for each call. On openbsd the mmap() address
45656 - * That means either we keep the mmap() open or we do a read() into a
45657 - * constant buffer
45658 + * That means either we keep the mmap() open or we do a read() into a
45659 + * constant buffer
45661 #define LOCAL_SEND_BUFSIZE (64 * 1024)
45662 static char *local_send_buffer = NULL;
45664 /* the remote side closed the connection before without shutdown request
45668 * if keep-alive is disabled */
45670 if (con->keep_alive == 0) {
45671 - SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
45672 + SSL_set_shutdown(sock->ssl, SSL_RECEIVED_SHUTDOWN);
45675 for(c = cq->first; c; c = c->next) {
45676 int chunk_finished = 0;
45687 if (c->mem->used == 0) {
45688 chunk_finished = 1;
45693 offset = c->mem->ptr + c->offset;
45694 toSend = c->mem->used - 1 - c->offset;
45698 * SSL_write man-page
45702 * When an SSL_write() operation has to be repeated because of
45703 * SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
45704 * repeated with the same arguments.
45707 + * SSL_write(..., 0) return 0 which is handle as an error (Success)
45708 + * checking toSend and not calling SSL_write() is simpler
45711 - if ((r = SSL_write(ssl, offset, toSend)) <= 0) {
45713 + if (toSend != 0 && (r = SSL_write(sock->ssl, offset, toSend)) <= 0) {
45716 - switch ((ssl_r = SSL_get_error(ssl, r))) {
45717 + switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
45718 case SSL_ERROR_WANT_WRITE:
45720 case SSL_ERROR_SYSCALL:
45721 /* perhaps we have error waiting in our error-queue */
45722 if (0 != (err = ERR_get_error())) {
45724 - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45725 + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45727 ERR_error_string(err, NULL));
45728 } while((err = ERR_get_error()));
45729 @@ -105,43 +177,43 @@
45733 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45734 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45740 /* neither error-queue nor errno ? */
45741 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
45742 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
45749 case SSL_ERROR_ZERO_RETURN:
45750 /* clean shutdown on the remote side */
45753 if (r == 0) return -2;
45758 while((err = ERR_get_error())) {
45759 - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45760 + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45762 ERR_error_string(err, NULL));
45770 cq->bytes_out += r;
45774 if (c->offset == (off_t)c->mem->used - 1) {
45775 chunk_finished = 1;
45782 @@ -150,7 +222,7 @@
45783 stat_cache_entry *sce = NULL;
45785 int write_wait = 0;
45788 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45789 log_error_write(srv, __FILE__, __LINE__, "sb",
45790 strerror(errno), c->file.name);
45791 @@ -164,13 +236,13 @@
45794 off_t offset = c->file.start + c->offset;
45795 - off_t toSend = c->file.length - c->offset;
45796 + off_t toSend = c->file.length - c->offset;
45798 if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
45801 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
45802 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed:", strerror(errno));
45808 @@ -183,13 +255,13 @@
45811 s = local_send_buffer;
45816 - if ((r = SSL_write(ssl, s, toSend)) <= 0) {
45818 + if ((r = SSL_write(sock->ssl, s, toSend)) <= 0) {
45821 - switch ((ssl_r = SSL_get_error(ssl, r))) {
45822 + switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
45823 case SSL_ERROR_WANT_WRITE:
45826 @@ -197,7 +269,7 @@
45827 /* perhaps we have error waiting in our error-queue */
45828 if (0 != (err = ERR_get_error())) {
45830 - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45831 + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45833 ERR_error_string(err, NULL));
45834 } while((err = ERR_get_error()));
45835 @@ -207,62 +279,62 @@
45839 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45840 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45846 /* neither error-queue nor errno ? */
45847 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
45848 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
45855 case SSL_ERROR_ZERO_RETURN:
45856 /* clean shutdown on the remote side */
45859 if (r == 0) return -2;
45864 while((err = ERR_get_error())) {
45865 - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45866 + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45868 ERR_error_string(err, NULL));
45876 cq->bytes_out += r;
45880 if (c->offset == c->file.length) {
45881 chunk_finished = 1;
45883 } while(!chunk_finished && !write_wait);
45889 log_error_write(srv, __FILE__, __LINE__, "s", "type not known");
45896 if (!chunk_finished) {
45897 /* not finished yet */
45907 - return chunks_written;
45908 + return NETWORK_STATUS_SUCCESS;
45912 --- ../lighttpd-1.4.11/src/network_solaris_sendfilev.c 2005-10-22 12:28:27.000000000 +0300
45913 +++ lighttpd-1.4.12/src/network_solaris_sendfilev.c 2006-07-16 00:26:04.000000000 +0300
45914 @@ -29,114 +29,34 @@
45918 - * a very simple sendfilev() interface for solaris which can be optimised a lot more
45919 + * a very simple sendfilev() interface for solaris which can be optimised a lot more
45920 * as solaris sendfilev() supports 'sending everythin in one syscall()'
45922 - * If you want such an interface and need the performance, just give me an account on
45925 + * If you want such an interface and need the performance, just give me an account on
45927 * - jan@kneschke.de
45931 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq) {
45932 +NETWORK_BACKEND_WRITE(solarissendfilev) {
45934 size_t chunks_written = 0;
45937 for(c = cq->first; c; c = c->next, chunks_written++) {
45938 int chunk_finished = 0;
45940 + network_status_t ret;
45943 - case MEM_CHUNK: {
45948 - size_t num_chunks, i;
45949 - struct iovec chunks[UIO_MAXIOV];
45952 - size_t num_bytes = 0;
45954 - /* we can't send more then SSIZE_MAX bytes in one chunk */
45956 - /* build writev list
45958 - * 1. limit: num_chunks < UIO_MAXIOV
45959 - * 2. limit: num_bytes < SSIZE_MAX
45961 - for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
45963 - for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
45964 - if (tc->mem->used == 0) {
45965 - chunks[i].iov_base = tc->mem->ptr;
45966 - chunks[i].iov_len = 0;
45968 - offset = tc->mem->ptr + tc->offset;
45969 - toSend = tc->mem->used - 1 - tc->offset;
45971 - chunks[i].iov_base = offset;
45973 - /* protect the return value of writev() */
45974 - if (toSend > SSIZE_MAX ||
45975 - num_bytes + toSend > SSIZE_MAX) {
45976 - chunks[i].iov_len = SSIZE_MAX - num_bytes;
45978 - num_chunks = i + 1;
45981 - chunks[i].iov_len = toSend;
45984 - num_bytes += toSend;
45988 - if ((r = writev(fd, chunks, num_chunks)) < 0) {
45998 - log_error_write(srv, __FILE__, __LINE__, "ssd",
45999 - "writev failed:", strerror(errno), fd);
46005 - /* check which chunks have been written */
46006 - cq->bytes_out += r;
46008 - for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46009 - if (r >= (ssize_t)chunks[i].iov_len) {
46011 - r -= chunks[i].iov_len;
46012 - tc->offset += chunks[i].iov_len;
46014 - if (chunk_finished) {
46015 - /* skip the chunks from further touches */
46016 - chunks_written++;
46019 - /* chunks_written + c = c->next is done in the for()*/
46020 - chunk_finished++;
46023 - /* partially written */
46026 - chunk_finished = 0;
46031 + ret = network_write_chunkqueue_writev_mem(srv, con, fd, cq, &c);
46033 + if (ret != NETWORK_STATUS_SUCCESS) {
46038 + chunk_finished = 1;
46045 @@ -144,25 +64,25 @@
46046 sendfilevec_t fvec;
46047 stat_cache_entry *sce = NULL;
46051 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46052 log_error_write(srv, __FILE__, __LINE__, "sb",
46053 strerror(errno), c->file.name);
46058 offset = c->file.start + c->offset;
46059 toSend = c->file.length - c->offset;
46062 if (offset > sce->st.st_size) {
46063 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
46069 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
46070 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
46076 @@ -170,44 +90,43 @@
46078 fvec.sfv_off = offset;
46079 fvec.sfv_len = toSend;
46082 /* Solaris sendfilev() */
46083 if (-1 == (r = sendfilev(fd, &fvec, 1, &written))) {
46084 if (errno != EAGAIN) {
46085 log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
46090 + return NETWORK_STATUS_FATAL_ERROR;
46099 c->offset += written;
46100 cq->bytes_out += written;
46103 if (c->offset == c->file.length) {
46104 chunk_finished = 1;
46112 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
46116 + return NETWORK_STATUS_FATAL_ERROR;
46120 if (!chunk_finished) {
46121 /* not finished yet */
46128 - return chunks_written;
46129 + return NETWORK_STATUS_SUCCESS;
46133 --- ../lighttpd-1.4.11/src/network_write.c 2005-10-22 12:27:56.000000000 +0300
46134 +++ lighttpd-1.4.12/src/network_write.c 2006-07-18 13:03:40.000000000 +0300
46136 #include <sys/types.h>
46137 #include <sys/stat.h>
46138 -#include <sys/time.h>
46142 -#include <unistd.h>
46143 #include <string.h>
46144 #include <stdlib.h>
46145 +#include <assert.h>
46147 #include "network.h"
46148 #include "fdevent.h"
46150 #include "stat_cache.h"
46152 #include "sys-socket.h"
46153 +#include "sys-files.h"
46155 #include "network_backends.h"
46159 #ifdef HAVE_SYS_FILIO_H
46160 # include <sys/filio.h>
46162 @@ -24,47 +27,92 @@
46163 #include <sys/resource.h>
46166 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq) {
46169 +* fill the chunkqueue will all the data that we can get
46171 +* this might be optimized into a readv() which uses the chunks
46174 +NETWORK_BACKEND_READ(read) {
46180 + * a EAGAIN is a successful read if we already read something to the chunkqueue
46182 + int read_something = 0;
46184 + /* use a chunk-size of 8k */
46188 + b = chunkqueue_get_append_buffer(cq);
46190 + buffer_prepare_copy(b, toread);
46192 + if (-1 == (r = read(sock->fd, b->ptr, toread))) {
46195 + /* remove the last chunk from the chunkqueue */
46196 + chunkqueue_remove_empty_last_chunk(cq);
46197 + return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
46199 + ERROR("oops, read from fd=%d failed: %s (%d)", sock->fd, strerror(errno), errno );
46201 + return NETWORK_STATUS_FATAL_ERROR;
46206 + chunkqueue_remove_empty_last_chunk(cq);
46207 + return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_CONNECTION_CLOSE;
46210 + read_something = 1;
46213 + b->ptr[b->used++] = '\0';
46214 + } while (r == toread);
46216 + return NETWORK_STATUS_SUCCESS;
46219 +NETWORK_BACKEND_WRITE(write) {
46221 size_t chunks_written = 0;
46224 for(c = cq->first; c; c = c->next) {
46225 int chunk_finished = 0;
46235 if (c->mem->used == 0) {
46236 chunk_finished = 1;
46241 offset = c->mem->ptr + c->offset;
46242 toSend = c->mem->used - 1 - c->offset;
46244 - if ((r = send(fd, offset, toSend, 0)) < 0) {
46245 - log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
46250 - if ((r = write(fd, offset, toSend)) < 0) {
46251 - log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
46255 + if ((r = write(sock->fd, offset, toSend)) < 0) {
46256 + log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), sock->fd);
46258 + return NETWORK_STATUS_FATAL_ERROR;
46264 cq->bytes_out += r;
46267 if (c->offset == (off_t)c->mem->used - 1) {
46268 chunk_finished = 1;
46275 @@ -76,93 +124,89 @@
46277 stat_cache_entry *sce = NULL;
46281 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46282 log_error_write(srv, __FILE__, __LINE__, "sb",
46283 strerror(errno), c->file.name);
46285 + return NETWORK_STATUS_FATAL_ERROR;
46289 offset = c->file.start + c->offset;
46290 toSend = c->file.length - c->offset;
46293 if (offset > sce->st.st_size) {
46294 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
46298 + return NETWORK_STATUS_FATAL_ERROR;
46301 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
46302 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
46306 + return NETWORK_STATUS_FATAL_ERROR;
46310 #if defined USE_MMAP
46311 if (MAP_FAILED == (p = mmap(0, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
46312 log_error_write(srv, __FILE__, __LINE__, "ss", "mmap failed: ", strerror(errno));
46318 + return NETWORK_STATUS_FATAL_ERROR;
46322 - if ((r = write(fd, p + offset, toSend)) <= 0) {
46323 + if ((r = write(sock->fd, p + offset, toSend)) <= 0) {
46324 log_error_write(srv, __FILE__, __LINE__, "ss", "write failed: ", strerror(errno));
46325 munmap(p, sce->st.st_size);
46327 + return NETWORK_STATUS_FATAL_ERROR;
46331 munmap(p, sce->st.st_size);
46333 buffer_prepare_copy(srv->tmp_buf, toSend);
46336 lseek(ifd, offset, SEEK_SET);
46337 if (-1 == (toSend = read(ifd, srv->tmp_buf->ptr, toSend))) {
46338 log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
46343 + return NETWORK_STATUS_FATAL_ERROR;
46347 - if (-1 == (r = send(fd, srv->tmp_buf->ptr, toSend, 0))) {
46348 + if (-1 == (r = send(sock->fd, srv->tmp_buf->ptr, toSend, 0))) {
46349 log_error_write(srv, __FILE__, __LINE__, "ss", "write: ", strerror(errno));
46353 + return NETWORK_STATUS_FATAL_ERROR;
46357 cq->bytes_out += r;
46360 if (c->offset == c->file.length) {
46361 chunk_finished = 1;
46370 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
46374 + return NETWORK_STATUS_FATAL_ERROR;
46378 if (!chunk_finished) {
46379 /* not finished yet */
46389 - return chunks_written;
46390 + return NETWORK_STATUS_SUCCESS;
46394 -network_write_init(void) {
46395 - p->write = network_write_write_chunkset;
46398 --- ../lighttpd-1.4.11/src/network_writev.c 2006-02-15 01:02:36.000000000 +0200
46399 +++ lighttpd-1.4.12/src/network_writev.c 2006-07-18 13:03:40.000000000 +0300
46400 @@ -28,10 +28,10 @@
46403 # if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__)
46404 -/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */
46405 +/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */
46406 # define UIO_MAXIOV 1024
46407 # elif defined(__sgi)
46408 -/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */
46409 +/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */
46410 # define UIO_MAXIOV 512
46411 # elif defined(__sun)
46412 /* Solaris (and SunOS?) defines IOV_MAX instead */
46413 @@ -51,105 +51,121 @@
46414 #define LOCAL_BUFFERING 1
46417 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq) {
46419 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem) {
46424 + size_t num_chunks, i;
46425 + struct iovec chunks[UIO_MAXIOV];
46426 + chunk *tc; /* transfer chunks */
46427 + size_t num_bytes = 0;
46429 + /* we can't send more then SSIZE_MAX bytes in one chunk */
46431 + /* build writev list
46433 + * 1. limit: num_chunks < UIO_MAXIOV
46434 + * 2. limit: num_bytes < SSIZE_MAX
46436 + for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
46438 + for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
46439 + if (tc->mem->used == 0) {
46440 + chunks[i].iov_base = tc->mem->ptr;
46441 + chunks[i].iov_len = 0;
46443 + offset = tc->mem->ptr + tc->offset;
46444 + toSend = tc->mem->used - 1 - tc->offset;
46446 + chunks[i].iov_base = offset;
46448 + /* protect the return value of writev() */
46449 + if (toSend > SSIZE_MAX ||
46450 + num_bytes + toSend > SSIZE_MAX) {
46451 + chunks[i].iov_len = SSIZE_MAX - num_bytes;
46453 + num_chunks = i + 1;
46456 + chunks[i].iov_len = toSend;
46459 + num_bytes += toSend;
46463 + if ((r = writev(sock->fd, chunks, num_chunks)) < 0) {
46466 + return NETWORK_STATUS_WAIT_FOR_EVENT;
46468 + return NETWORK_STATUS_INTERRUPTED;
46471 + return NETWORK_STATUS_CONNECTION_CLOSE;
46473 + log_error_write(srv, __FILE__, __LINE__, "ssd",
46474 + "writev failed:", strerror(errno), sock->fd);
46476 + return NETWORK_STATUS_FATAL_ERROR;
46480 + cq->bytes_out += r;
46482 + /* check which chunks have been written */
46484 + for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46485 + if (r >= (ssize_t)chunks[i].iov_len) {
46487 + r -= chunks[i].iov_len;
46488 + tc->offset += chunks[i].iov_len;
46490 + /* partially written */
46494 + return NETWORK_STATUS_WAIT_FOR_EVENT;
46498 + /* all chunks have been pushed out */
46499 + return NETWORK_STATUS_SUCCESS;
46502 +NETWORK_BACKEND_WRITE(writev) {
46504 size_t chunks_written = 0;
46507 for(c = cq->first; c; c = c->next) {
46508 int chunk_finished = 0;
46510 + network_status_t ret;
46513 - case MEM_CHUNK: {
46518 - size_t num_chunks, i;
46519 - struct iovec chunks[UIO_MAXIOV];
46521 - size_t num_bytes = 0;
46523 - /* we can't send more then SSIZE_MAX bytes in one chunk */
46525 - /* build writev list
46527 - * 1. limit: num_chunks < UIO_MAXIOV
46528 - * 2. limit: num_bytes < SSIZE_MAX
46530 - for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
46532 - for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
46533 - if (tc->mem->used == 0) {
46534 - chunks[i].iov_base = tc->mem->ptr;
46535 - chunks[i].iov_len = 0;
46537 - offset = tc->mem->ptr + tc->offset;
46538 - toSend = tc->mem->used - 1 - tc->offset;
46540 - chunks[i].iov_base = offset;
46542 - /* protect the return value of writev() */
46543 - if (toSend > SSIZE_MAX ||
46544 - num_bytes + toSend > SSIZE_MAX) {
46545 - chunks[i].iov_len = SSIZE_MAX - num_bytes;
46547 - num_chunks = i + 1;
46550 - chunks[i].iov_len = toSend;
46553 - num_bytes += toSend;
46557 - if ((r = writev(fd, chunks, num_chunks)) < 0) {
46567 - log_error_write(srv, __FILE__, __LINE__, "ssd",
46568 - "writev failed:", strerror(errno), fd);
46574 - cq->bytes_out += r;
46576 + ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
46578 - /* check which chunks have been written */
46580 - for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46581 - if (r >= (ssize_t)chunks[i].iov_len) {
46583 - r -= chunks[i].iov_len;
46584 - tc->offset += chunks[i].iov_len;
46586 + /* check which chunks are finished now */
46587 + for (tc = c; tc; tc = tc->next) {
46588 + /* finished the chunk */
46589 + if (tc->offset == tc->mem->used - 1) {
46590 + /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
46591 if (chunk_finished) {
46592 - /* skip the chunks from further touches */
46593 - chunks_written++;
46596 - /* chunks_written + c = c->next is done in the for()*/
46597 - chunk_finished++;
46598 + chunk_finished = 1;
46601 - /* partially written */
46604 - chunk_finished = 0;
46611 + if (ret != NETWORK_STATUS_SUCCESS) {
46620 @@ -159,26 +175,26 @@
46621 #define KByte * 1024
46622 #define MByte * 1024 KByte
46623 #define GByte * 1024 MByte
46624 - const off_t we_want_to_mmap = 512 KByte;
46625 + const off_t we_want_to_mmap = 512 KByte;
46626 char *start = NULL;
46628 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46629 log_error_write(srv, __FILE__, __LINE__, "sb",
46630 strerror(errno), c->file.name);
46632 + return NETWORK_STATUS_FATAL_ERROR;
46635 abs_offset = c->file.start + c->offset;
46638 if (abs_offset > sce->st.st_size) {
46639 - log_error_write(srv, __FILE__, __LINE__, "sb",
46640 + log_error_write(srv, __FILE__, __LINE__, "sb",
46641 "file was shrinked:", c->file.name);
46645 + return NETWORK_STATUS_FATAL_ERROR;
46648 - /* mmap the buffer
46650 + /* mmap the buffer
46652 * - new mmap as the we are at the end of the last one */
46653 if (c->file.mmap.start == MAP_FAILED ||
46654 abs_offset == (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
46655 @@ -188,7 +204,7 @@
46656 * adaptive mem-mapping
46658 * we mmap() the whole file. If someone has alot large files and 32bit
46659 - * machine the virtual address area will be unrun and we will have a failing
46660 + * machine the virtual address area will be unrun and we will have a failing
46663 * only mmap 16M in one chunk and move the window as soon as we have finished
46664 @@ -234,8 +250,8 @@
46665 if (-1 == c->file.fd) { /* open the file if not already open */
46666 if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
46667 log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno));
46671 + return NETWORK_STATUS_FATAL_ERROR;
46674 fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
46675 @@ -245,10 +261,10 @@
46676 if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
46677 /* close it here, otherwise we'd have to set FD_CLOEXEC */
46679 - log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
46680 + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
46681 strerror(errno), c->file.name, c->file.fd);
46684 + return NETWORK_STATUS_FATAL_ERROR;
46687 c->file.mmap.length = to_mmap;
46688 @@ -258,7 +274,7 @@
46689 #ifdef HAVE_MADVISE
46690 /* don't advise files < 64Kb */
46691 if (c->file.mmap.length > (64 KByte)) {
46692 - /* darwin 7 is returning EINVAL all the time and I don't know how to
46693 + /* darwin 7 is returning EINVAL all the time and I don't know how to
46694 * detect this at runtime.i
46696 * ignore the return value for now */
46697 @@ -274,12 +290,12 @@
46698 toSend = (c->file.mmap.offset + c->file.mmap.length) - (abs_offset);
46701 - log_error_write(srv, __FILE__, __LINE__, "soooo",
46702 + log_error_write(srv, __FILE__, __LINE__, "soooo",
46703 "toSend is negative:",
46705 c->file.mmap.length,
46707 - c->file.mmap.offset);
46708 + c->file.mmap.offset);
46709 assert(toSend < 0);
46712 @@ -289,7 +305,7 @@
46713 start = c->file.mmap.start;
46716 - if ((r = write(fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
46717 + if ((r = write(sock->fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
46721 @@ -297,18 +313,18 @@
46726 + return NETWORK_STATUS_CONNECTION_CLOSE;
46728 - log_error_write(srv, __FILE__, __LINE__, "ssd",
46729 - "write failed:", strerror(errno), fd);
46732 + log_error_write(srv, __FILE__, __LINE__, "ssd",
46733 + "write failed:", strerror(errno), sock->fd);
46735 + return NETWORK_STATUS_FATAL_ERROR;
46741 cq->bytes_out += r;
46744 if (c->offset == c->file.length) {
46745 chunk_finished = 1;
46747 @@ -318,26 +334,26 @@
46748 c->file.mmap.start = MAP_FAILED;
46758 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
46762 + return NETWORK_STATUS_FATAL_ERROR;
46766 if (!chunk_finished) {
46767 /* not finished yet */
46777 - return chunks_written;
46778 + return NETWORK_STATUS_SUCCESS;
46782 --- ../lighttpd-1.4.11/src/plugin.c 2006-02-08 14:00:54.000000000 +0200
46783 +++ lighttpd-1.4.12/src/plugin.c 2006-07-16 00:26:04.000000000 +0300
46784 @@ -13,27 +13,27 @@
46785 #include <valgrind/valgrind.h>
46795 * if you change this enum to add a new callback, be sure
46796 * - that PLUGIN_FUNC_SIZEOF is the last entry
46797 * - that you add PLUGIN_TO_SLOT twice:
46798 - * 1. as callback-dispatcher
46799 + * 1. as callback-dispatcher
46800 * 2. in plugins_call_init()
46812 - PLUGIN_FUNC_HANDLE_URI_CLEAN,
46813 - PLUGIN_FUNC_HANDLE_URI_RAW,
46814 + PLUGIN_FUNC_HANDLE_URI_CLEAN,
46815 + PLUGIN_FUNC_HANDLE_URI_RAW,
46816 PLUGIN_FUNC_HANDLE_REQUEST_DONE,
46817 PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
46818 PLUGIN_FUNC_HANDLE_TRIGGER,
46819 @@ -44,38 +44,42 @@
46820 PLUGIN_FUNC_HANDLE_DOCROOT,
46821 PLUGIN_FUNC_HANDLE_PHYSICAL,
46822 PLUGIN_FUNC_CONNECTION_RESET,
46823 - PLUGIN_FUNC_INIT,
46824 + PLUGIN_FUNC_INIT,
46825 PLUGIN_FUNC_CLEANUP,
46826 PLUGIN_FUNC_SET_DEFAULTS,
46832 static plugin *plugin_init(void) {
46836 p = calloc(1, sizeof(*p));
46839 + p->required_plugins = array_init();
46844 static void plugin_free(plugin *p) {
46845 int use_dlclose = 1;
46846 if (p->name) buffer_free(p->name);
46848 + array_free(p->required_plugins);
46849 #ifdef HAVE_VALGRIND_VALGRIND_H
46850 /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
46853 #ifndef LIGHTTPD_STATIC
46854 - if (use_dlclose && p->lib) {
46856 + if (use_dlclose && p->lib) {
46858 FreeLibrary(p->lib);
46869 @@ -89,17 +93,17 @@
46870 srv->plugins.size += 4;
46871 srv->plugins.ptr = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
46875 ps = srv->plugins.ptr;
46876 ps[srv->plugins.used++] = p;
46891 #ifdef LIGHTTPD_STATIC
46892 @@ -121,30 +125,35 @@
46894 int plugins_load(server *srv) {
46899 int (*init)(plugin *pl);
46907 for (i = 0; i < srv->srvconf.modules->used; i++) {
46908 data_string *d = (data_string *)srv->srvconf.modules->data[i];
46909 char *modules = d->value->ptr;
46912 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
46914 buffer_append_string(srv->tmp_buf, "/");
46915 buffer_append_string(srv->tmp_buf, modules);
46916 -#if defined(__WIN32) || defined(__CYGWIN__)
46917 +#if defined(_WIN32) || defined(__CYGWIN__)
46918 buffer_append_string(srv->tmp_buf, ".dll");
46920 buffer_append_string(srv->tmp_buf, ".so");
46927 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
46930 - FORMAT_MESSAGE_ALLOCATE_BUFFER |
46931 + FORMAT_MESSAGE_ALLOCATE_BUFFER |
46932 FORMAT_MESSAGE_FROM_SYSTEM,
46935 @@ -152,36 +161,36 @@
46936 (LPTSTR) &lpMsgBuf,
46939 - log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
46940 + log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
46941 lpMsgBuf, srv->tmp_buf);
46952 if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_LAZY))) {
46953 - log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
46954 + log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
46955 srv->tmp_buf, dlerror());
46966 buffer_reset(srv->tmp_buf);
46967 buffer_copy_string(srv->tmp_buf, modules);
46968 buffer_append_string(srv->tmp_buf, "_plugin_init");
46972 init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
46974 if (init == NULL) {
46977 - FORMAT_MESSAGE_ALLOCATE_BUFFER |
46978 + FORMAT_MESSAGE_ALLOCATE_BUFFER |
46979 FORMAT_MESSAGE_FROM_SYSTEM,
46982 @@ -190,7 +199,7 @@
46985 log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
46991 @@ -203,24 +212,43 @@
46993 if ((error = dlerror()) != NULL) {
46994 log_error_write(srv, __FILE__, __LINE__, "s", error);
47004 log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin init failed" );
47011 log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin loaded" );
47013 + /* check if the required plugin is loaded */
47014 + for (k = 0; k < p->required_plugins->used; k++) {
47015 + data_string *req = (data_string *)p->required_plugins->data[k];
47017 + for (j = 0; j < i; j++) {
47018 + data_string *mod = (data_string *)srv->srvconf.modules->data[j];
47020 + if (buffer_is_equal(req->value, mod->value)) break;
47025 + log_error_write(srv, __FILE__, __LINE__, "ssbs", modules, "failed to load. required plugin", req->value, "was not loaded" );
47032 plugins_register(srv, p);
47039 @@ -253,8 +281,8 @@
47043 - * plugins that use
47045 + * plugins that use
47048 * - connection *con
47049 * - void *p_d (plugin_data *)
47050 @@ -301,12 +329,12 @@
47054 - * plugins that use
47056 + * plugins that use
47059 * - void *p_d (plugin_data *)
47063 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
47064 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
47065 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
47066 @@ -314,18 +342,18 @@
47068 #undef PLUGIN_TO_SLOT
47079 handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
47084 ps = srv->plugins.ptr;
47087 for (i = 0; i < srv->plugins.used; i++) {
47089 if (p->handle_fdevent) {
47090 @@ -344,34 +372,34 @@
47096 return HANDLER_GO_ON;
47102 * - call init function of all plugins to init the plugin-internals
47103 * - added each plugin that supports has callback to the corresponding slot
47106 * - is only called once.
47109 handler_t plugins_call_init(server *srv) {
47114 ps = srv->plugins.ptr;
47120 srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
47123 for (i = 0; i < srv->plugins.used; i++) {
47125 /* check which calls are supported */
47131 #define PLUGIN_TO_SLOT(x, y) \
47133 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
47134 @@ -384,11 +412,11 @@
47141 - PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
47142 - PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
47146 + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
47147 + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
47148 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
47149 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
47150 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
47151 @@ -402,19 +430,19 @@
47152 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
47153 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
47154 #undef PLUGIN_TO_SLOT
47158 if (NULL == (p->data = p->init())) {
47159 - log_error_write(srv, __FILE__, __LINE__, "sb",
47160 + log_error_write(srv, __FILE__, __LINE__, "sb",
47161 "plugin-init failed for module", p->name);
47162 return HANDLER_ERROR;
47166 /* used for con->mode, DIRECT == 0, plugins above that */
47167 ((plugin_data *)(p->data))->id = i + 1;
47170 if (p->version != LIGHTTPD_VERSION_ID) {
47171 - log_error_write(srv, __FILE__, __LINE__, "sb",
47172 + log_error_write(srv, __FILE__, __LINE__, "sb",
47173 "plugin-version doesn't match lighttpd-version for", p->name);
47174 return HANDLER_ERROR;
47176 @@ -422,29 +450,46 @@
47182 return HANDLER_GO_ON;
47186 + * get the config-storage of the named plugin
47188 +void *plugin_get_config(server *srv, const char *name) {
47191 + for (i = 0; i < srv->plugins.used; i++) {
47192 + plugin *p = ((plugin **)srv->plugins.ptr)[i];
47194 + if (buffer_is_equal_string(p->name, name, strlen(name))) {
47202 void plugins_free(server *srv) {
47204 plugins_call_cleanup(srv);
47207 for (i = 0; i < srv->plugins.used; i++) {
47208 plugin *p = ((plugin **)srv->plugins.ptr)[i];
47215 for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
47216 plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
47219 if (slot) free(slot);
47223 free(srv->plugin_slots);
47224 srv->plugin_slots = NULL;
47227 free(srv->plugins.ptr);
47228 srv->plugins.ptr = NULL;
47229 srv->plugins.used = 0;
47230 --- ../lighttpd-1.4.11/src/plugin.h 2005-08-15 12:28:56.000000000 +0300
47231 +++ lighttpd-1.4.12/src/plugin.h 2006-07-16 00:26:04.000000000 +0300
47234 #define INIT_FUNC(x) \
47237 + * The PATCH_OPTION() macro is used in the patch_connection() functions
47238 + * of the modules to update the config object for the current request.
47240 +#define PATCH_OPTION(x) \
47243 #define FREE_FUNC SERVER_FUNC
47244 #define TRIGGER_FUNC SERVER_FUNC
47245 @@ -25,19 +31,19 @@
47246 #define URIHANDLER_FUNC CONNECTION_FUNC
47248 #define PLUGIN_DATA size_t id
47255 buffer *name; /* name of the plugin */
47259 handler_t (* set_defaults) (server *srv, void *p_d);
47260 handler_t (* cleanup) (server *srv, void *p_d);
47261 /* is called ... */
47262 handler_t (* handle_trigger) (server *srv, void *p_d); /* once a second */
47263 handler_t (* handle_sighup) (server *srv, void *p_d); /* at a signup */
47266 handler_t (* handle_uri_raw) (server *srv, connection *con, void *p_d); /* after uri_raw is set */
47267 handler_t (* handle_uri_clean) (server *srv, connection *con, void *p_d); /* after uri is set */
47268 handler_t (* handle_docroot) (server *srv, connection *con, void *p_d); /* getting the document-root */
47269 @@ -45,20 +51,22 @@
47270 handler_t (* handle_request_done) (server *srv, connection *con, void *p_d); /* at the end of a request */
47271 handler_t (* handle_connection_close)(server *srv, connection *con, void *p_d); /* at the end of a connection */
47272 handler_t (* handle_joblist) (server *srv, connection *con, void *p_d); /* after all events are handled */
47276 - handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);
47278 - /* when a handler for the request
47282 + handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);
47284 + /* when a handler for the request
47287 handler_t (* handle_subrequest) (server *srv, connection *con, void *p_d); /* */
47288 handler_t (* connection_reset) (server *srv, connection *con, void *p_d); /* */
47292 /* dlopen handle */
47295 + array *required_plugins;
47298 int plugins_load(server *srv);
47300 int config_patch_connection(server *srv, connection *con, comp_key_t comp);
47301 int config_check_cond(server *srv, connection *con, data_config *dc);
47302 int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n);
47303 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result);
47305 +void *plugin_get_config(server *srv, const char *name);
47308 --- ../lighttpd-1.4.11/src/proc_open.c 2005-08-11 01:26:39.000000000 +0300
47309 +++ lighttpd-1.4.12/src/proc_open.c 2006-07-16 00:26:04.000000000 +0300
47310 @@ -13,13 +13,13 @@
47316 /* {{{ win32 stuff */
47317 # define SHELLENV "ComSpec"
47318 # define SECURITY_DC , SECURITY_ATTRIBUTES *security
47319 # define SECURITY_CC , security
47320 # define pipe(pair) (CreatePipe(&pair[0], &pair[1], security, 2048L) ? 0 : -1)
47321 -static inline HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
47322 +static HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
47324 HANDLE copy, self = GetCurrentProcess();
47326 @@ -148,11 +148,14 @@
47329 SECURITY_ATTRIBUTES security;
47330 - const char *shell;
47331 + const char *shell = NULL;
47332 + const char *windir = NULL;
47335 - if (NULL == (shell = getenv(SHELLENV))) {
47336 - fprintf(stderr, "env %s is required", SHELLENV);
47337 + if (NULL == (shell = getenv(SHELLENV)) &&
47338 + NULL == (windir = getenv("SystemRoot")) &&
47339 + NULL == (windir = getenv("windir"))) {
47340 + fprintf(stderr, "One of %s,%%SystemRoot,%%windir is required", SHELLENV);
47344 @@ -177,17 +180,23 @@
47345 memset(&pi, 0, sizeof(pi));
47347 cmdline = buffer_init();
47348 - buffer_append_string(cmdline, shell);
47350 + buffer_append_string(cmdline, shell);
47352 + buffer_append_string(cmdline, windir);
47353 + buffer_append_string(cmdline, "\\system32\\cmd.exe");
47355 buffer_append_string_len(cmdline, CONST_STR_LEN(" /c "));
47356 buffer_append_string(cmdline, command);
47357 procok = CreateProcess(NULL, cmdline->ptr, &security, &security, TRUE,
47358 NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
47359 - buffer_free(cmdline);
47361 if (FALSE == procok) {
47362 - fprintf(stderr, "failed to CreateProcess");
47363 + fprintf(stderr, "failed to CreateProcess: %s", cmdline->ptr);
47364 + buffer_free(cmdline);
47367 + buffer_free(cmdline);
47369 proc->child = pi.hProcess;
47370 CloseHandle(pi.hThread);
47371 @@ -226,8 +235,7 @@
47374 if (NULL == (shell = getenv(SHELLENV))) {
47375 - fprintf(stderr, "env %s is required", SHELLENV);
47377 + shell = "/bin/sh";
47380 if (proc_open_pipes(proc) != 0) {
47381 @@ -262,11 +270,11 @@
47385 -#endif /* WIN32 */
47386 +#endif /* _WIN32 */
47388 /* {{{ proc_read_fd_to_buffer */
47389 static void proc_read_fd_to_buffer(int fd, buffer *b) {
47391 + int s; /* win32 has not ssize_t */
47394 buffer_prepare_append(b, 512);
47395 --- ../lighttpd-1.4.11/src/proc_open.h 2005-08-11 01:26:39.000000000 +0300
47396 +++ lighttpd-1.4.12/src/proc_open.h 2006-07-16 00:26:04.000000000 +0300
47399 #include "buffer.h"
47403 #include <windows.h>
47404 typedef HANDLE descriptor_t;
47405 typedef HANDLE proc_pid_t;
47406 --- ../lighttpd-1.4.11/src/request.c 2006-03-05 11:58:09.000000000 +0200
47407 +++ lighttpd-1.4.12/src/request.c 2006-07-18 13:03:40.000000000 +0300
47408 @@ -10,15 +10,17 @@
47409 #include "keyvalue.h"
47412 +#include "sys-strings.h"
47414 static int request_check_hostname(server *srv, connection *con, buffer *host) {
47415 enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
47420 - int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
47421 + int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
47428 @@ -32,17 +34,17 @@
47429 * IPv6address = "[" ... "]"
47435 if (!host || host->used == 0) return 0;
47438 host_len = host->used - 1;
47442 if (host->ptr[0] == '[') {
47443 char *c = host->ptr + 1;
47447 /* check portnumber */
47448 for (; *c && *c != ']'; c++) {
47450 @@ -53,12 +55,12 @@
47463 if (*(c+1) == ':') {
47464 for (c += 2; *c; c++) {
47465 @@ -69,39 +71,39 @@
47471 if (NULL != (colon = memchr(host->ptr, ':', host_len))) {
47472 char *c = colon + 1;
47475 /* check portnumber */
47477 if (!light_isdigit(*c)) return -1;
47481 /* remove the port from the host-len */
47482 host_len = colon - host->ptr;
47486 /* Host is empty */
47487 if (host_len == 0) return -1;
47490 /* scan from the right and skip the \0 */
47491 for (i = host_len - 1; i + 1 > 0; i--) {
47492 const char c = host->ptr[i];
47498 /* only switch stage, if this is not the last character */
47499 if (i != host_len - 1) {
47500 if (label_len == 0) {
47505 /* check the first character at right of the dot */
47507 if (!light_isalpha(host->ptr[i+1])) {
47511 } else if (!light_isdigit(host->ptr[i+1])) {
47513 @@ -111,9 +113,9 @@
47519 stage = DOMAINLABEL;
47524 } else if (i == 0) {
47525 @@ -135,7 +137,7 @@
47534 @@ -143,7 +145,7 @@
47535 if (label_len == 0) {
47542 } else if (!light_isdigit(c)) {
47543 @@ -156,12 +158,12 @@
47544 if (label_len == 0) {
47549 /* c is either - or alphanum here */
47550 if ('-' == host->ptr[i+1]) {
47557 } else if (i == 0) {
47558 @@ -176,20 +178,20 @@
47569 /* a IP has to consist of 4 parts */
47570 if (is_ip == 1 && level != 3) {
47575 if (label_len == 0) {
47583 @@ -201,53 +203,53 @@
47593 * val1, val2, val3, val4
47596 * into a array (more or less a explode() incl. striping of whitespaces
47600 if (b->used == 0) return 0;
47606 for (i =0; i < b->used - 1; ) {
47607 char *start = NULL, *end = NULL;
47616 for (; (*s == ' ' || *s == '\t') && i < b->used - 1; i++, s++);
47623 case 1: /* value */
47627 for (; *s != ',' && i < b->used - 1; i++, s++);
47631 for (; (*end == ' ' || *end == '\t') && end > start; end--);
47634 if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
47635 ds = data_string_init();
47638 buffer_copy_string_len(ds->value, start, end-start+1);
47639 array_insert_unique(vals, (data_unset *)ds);
47647 /* end of string */
47653 @@ -263,7 +265,7 @@
47654 if (c <= 32) return 0;
47655 if (c == 127) return 0;
47656 if (c == 255) return 0;
47662 @@ -271,28 +273,28 @@
47663 char *uri = NULL, *proto = NULL, *method = NULL, con_length_set;
47664 int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding;
47665 char *value = NULL, *key = NULL;
47668 enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_KEEPALIVE, HTTP_CONNECTION_CLOSE } keep_alive_set = HTTP_CONNECTION_UNSET;
47674 int request_line_stage = 0;
47681 data_string *ds = NULL;
47684 - * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
47685 - * Option : "^([-a-zA-Z]+): (.+)$"
47688 + * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
47689 + * Option : "^([-a-zA-Z]+): (.+)$"
47693 if (con->conf.log_request_header) {
47694 - log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
47696 - "request-len:", con->request.request->used,
47697 + log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
47698 + "fd:", con->sock->fd,
47699 + "request-len:", con->request.request->used,
47700 "\n", con->request.request);
47703 @@ -300,13 +302,13 @@
47704 con->request.request->ptr[0] == '\r' &&
47705 con->request.request->ptr[1] == '\n') {
47706 /* we are in keep-alive and might get \r\n after a previous POST request.*/
47709 buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, con->request.request->used - 1 - 2);
47711 /* fill the local request buffer */
47712 buffer_copy_string_buffer(con->parse_request, con->request.request);
47716 keep_alive_set = 0;
47717 con_length_set = 0;
47719 @@ -318,25 +320,25 @@
47721 for (i = 0, first = 0; i < con->parse_request->used && line == 0; i++) {
47722 char *cur = con->parse_request->ptr + i;
47728 if (con->parse_request->ptr[i+1] == '\n') {
47735 con->parse_request->ptr[i] = '\0';
47736 con->parse_request->ptr[i+1] = '\0';
47739 buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
47742 if (request_line_stage != 2) {
47743 con->http_status = 400;
47744 con->response.keep_alive = 0;
47745 con->keep_alive = 0;
47748 if (srv->srvconf.log_request_header_on_error) {
47749 log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
47750 log_error_write(srv, __FILE__, __LINE__, "Sb",
47751 @@ -345,36 +347,36 @@
47757 proto = con->parse_request->ptr + first;
47761 *(proto - 1) = '\0';
47764 /* we got the first one :) */
47765 if (-1 == (r = get_http_method_key(method))) {
47766 con->http_status = 501;
47767 con->response.keep_alive = 0;
47768 con->keep_alive = 0;
47771 if (srv->srvconf.log_request_header_on_error) {
47772 log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
47773 log_error_write(srv, __FILE__, __LINE__, "Sb",
47774 "request-header:\n",
47775 con->request.request);
47783 con->request.http_method = r;
47790 * HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
47794 if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) {
47795 char * major = proto + sizeof("HTTP/") - 1;
47796 char * minor = strchr(major, '.');
47797 @@ -413,10 +415,10 @@
47800 if (major_num == 1 && minor_num == 1) {
47801 - con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0;
47802 + con->request.http_version = HTTP_VERSION_1_1;
47803 } else if (major_num == 1 && minor_num == 0) {
47804 con->request.http_version = HTTP_VERSION_1_0;
47807 con->http_status = 505;
47809 if (srv->srvconf.log_request_header_on_error) {
47810 @@ -439,30 +441,30 @@
47816 if (0 == strncmp(uri, "http://", 7) &&
47817 NULL != (nuri = strchr(uri + 7, '/'))) {
47818 /* ignore the host-part */
47821 buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
47823 /* everything looks good so far */
47824 buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
47828 /* check uri for invalid characters */
47829 for (j = 0; j < con->request.uri->used - 1; j++) {
47830 if (!request_uri_is_valid_char(con->request.uri->ptr[j])) {
47831 unsigned char buf[2];
47832 con->http_status = 400;
47833 con->keep_alive = 0;
47836 if (srv->srvconf.log_request_header_on_error) {
47837 buf[0] = con->request.uri->ptr[j];
47841 if (con->request.uri->ptr[j] > 32 &&
47842 - con->request.uri->ptr[j] != 127) {
47843 + con->request.uri->ptr[j] != 127) {
47844 /* the character is printable -> print it */
47845 log_error_write(srv, __FILE__, __LINE__, "ss",
47846 "invalid character in URI -> 400",
47847 @@ -473,20 +475,20 @@
47848 "invalid character in URI -> 400",
47849 con->request.uri->ptr[j]);
47853 log_error_write(srv, __FILE__, __LINE__, "Sb",
47854 "request-header:\n",
47855 con->request.request);
47864 buffer_copy_string_buffer(con->request.orig_uri, con->request.uri);
47867 con->http_status = 0;
47873 @@ -494,14 +496,14 @@
47876 switch(request_line_stage) {
47880 - method = con->parse_request->ptr + first;
47881 + method = con->parse_request->ptr + first;
47886 - uri = con->parse_request->ptr + first;
47887 + uri = con->parse_request->ptr + first;
47891 @@ -509,7 +511,7 @@
47892 con->http_status = 400;
47893 con->response.keep_alive = 0;
47894 con->keep_alive = 0;
47897 if (srv->srvconf.log_request_header_on_error) {
47898 log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
47899 log_error_write(srv, __FILE__, __LINE__, "Sb",
47900 @@ -518,12 +520,12 @@
47906 request_line_stage++;
47914 if (con->request.uri->used == 1) {
47915 @@ -540,30 +542,30 @@
47921 for (; i < con->parse_request->used && !done; i++) {
47922 char *cur = con->parse_request->ptr + i;
47931 * 1*<any CHAR except CTLs or separators>
47932 * CTLs == 0-31 + 127
47944 if (is_ws_after_key == 0) {
47945 key_len = i - first;
47947 is_ws_after_key = 0;
47953 @@ -584,8 +586,8 @@
47954 con->http_status = 400;
47955 con->keep_alive = 0;
47956 con->response.keep_alive = 0;
47958 - log_error_write(srv, __FILE__, __LINE__, "sbsds",
47960 + log_error_write(srv, __FILE__, __LINE__, "sbsds",
47961 "invalid character in key", con->request.request, cur, *cur, "-> 400");
47964 @@ -594,13 +596,13 @@
47976 key_len = i - first;
47979 /* skip every thing up to the : */
47980 for (j = 1; !got_colon; j++) {
47981 switch(con->parse_request->ptr[j + i]) {
47982 @@ -610,40 +612,40 @@
47997 if (srv->srvconf.log_request_header_on_error) {
47998 log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
47999 log_error_write(srv, __FILE__, __LINE__, "Sb",
48000 "request-header:\n",
48001 con->request.request);
48005 con->http_status = 400;
48006 con->response.keep_alive = 0;
48007 con->keep_alive = 0;
48017 if (con->parse_request->ptr[i+1] == '\n' && i == first) {
48018 /* End of Header */
48019 con->parse_request->ptr[i] = '\0';
48020 con->parse_request->ptr[i+1] = '\0';
48031 if (srv->srvconf.log_request_header_on_error) {
48032 @@ -652,7 +654,7 @@
48033 "request-header:\n",
48034 con->request.request);
48038 con->http_status = 400;
48039 con->keep_alive = 0;
48040 con->response.keep_alive = 0;
48041 @@ -693,16 +695,16 @@
48042 con->http_status = 400;
48043 con->keep_alive = 0;
48044 con->response.keep_alive = 0;
48047 if (srv->srvconf.log_request_header_on_error) {
48048 - log_error_write(srv, __FILE__, __LINE__, "sbsds",
48049 + log_error_write(srv, __FILE__, __LINE__, "sbsds",
48050 "CTL character in key", con->request.request, cur, *cur, "-> 400");
48052 log_error_write(srv, __FILE__, __LINE__, "Sb",
48053 "request-header:\n",
48054 con->request.request);
48061 @@ -710,25 +712,25 @@
48067 if (con->parse_request->ptr[i+1] == '\n') {
48068 /* End of Headerline */
48069 con->parse_request->ptr[i] = '\0';
48070 con->parse_request->ptr[i+1] = '\0';
48078 if (srv->srvconf.log_request_header_on_error) {
48079 log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
48082 log_error_write(srv, __FILE__, __LINE__, "Sb",
48083 "request-header:\n",
48084 con->request.request);
48089 con->http_status = 400;
48090 con->keep_alive = 0;
48091 con->response.keep_alive = 0;
48092 @@ -738,9 +740,9 @@
48095 key = con->parse_request->ptr + first;
48098 s_len = cur - value;
48103 if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
48104 @@ -748,86 +750,87 @@
48106 buffer_copy_string_len(ds->key, key, key_len);
48107 buffer_copy_string_len(ds->value, value, s_len);
48109 - /* retreive values
48113 + /* retreive values
48116 * the list of options is sorted to simplify the search
48120 if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
48128 vals = srv->split_vals;
48133 http_request_split_value(vals, ds->value);
48136 for (vi = 0; vi < vals->used; vi++) {
48137 data_string *dsv = (data_string *)vals->data[vi];
48140 if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
48141 keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
48145 } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
48146 keep_alive_set = HTTP_CONNECTION_CLOSE;
48154 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
48156 unsigned long int r;
48160 if (con_length_set) {
48161 con->http_status = 400;
48162 con->keep_alive = 0;
48165 if (srv->srvconf.log_request_header_on_error) {
48166 - log_error_write(srv, __FILE__, __LINE__, "s",
48167 + log_error_write(srv, __FILE__, __LINE__, "s",
48168 "duplicate Content-Length-header -> 400");
48169 log_error_write(srv, __FILE__, __LINE__, "Sb",
48170 "request-header:\n",
48171 con->request.request);
48173 + ds->free((data_unset *) ds);
48178 if (ds->value->used == 0) SEGFAULT();
48181 for (j = 0; j < ds->value->used - 1; j++) {
48182 char c = ds->value->ptr[j];
48183 if (!isdigit((unsigned char)c)) {
48184 - log_error_write(srv, __FILE__, __LINE__, "sbs",
48185 + log_error_write(srv, __FILE__, __LINE__, "sbs",
48186 "content-length broken:", ds->value, "-> 400");
48189 con->http_status = 400;
48190 con->keep_alive = 0;
48193 array_insert_unique(con->request.headers, (data_unset *)ds);
48199 r = strtoul(ds->value->ptr, &err, 10);
48202 if (*err == '\0') {
48203 con_length_set = 1;
48204 con->request.content_length = r;
48206 - log_error_write(srv, __FILE__, __LINE__, "sbs",
48207 + log_error_write(srv, __FILE__, __LINE__, "sbs",
48208 "content-length broken:", ds->value, "-> 400");
48211 con->http_status = 400;
48212 con->keep_alive = 0;
48215 array_insert_unique(con->request.headers, (data_unset *)ds);
48218 @@ -838,23 +841,24 @@
48220 con->http_status = 400;
48221 con->keep_alive = 0;
48224 if (srv->srvconf.log_request_header_on_error) {
48225 - log_error_write(srv, __FILE__, __LINE__, "s",
48226 + log_error_write(srv, __FILE__, __LINE__, "s",
48227 "duplicate Content-Type-header -> 400");
48228 log_error_write(srv, __FILE__, __LINE__, "Sb",
48229 "request-header:\n",
48230 con->request.request);
48232 + ds->free((data_unset *) ds);
48235 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
48236 - /* HTTP 2616 8.2.3
48237 + /* HTTP 2616 8.2.3
48238 * Expect: 100-continue
48241 * -> (10.1.1) 100 (read content, process request, send final status-code)
48242 * -> (10.4.18) 417 (close)
48245 * (not handled at all yet, we always send 417 here)
48247 * What has to be added ?
48248 @@ -863,10 +867,10 @@
48254 con->http_status = 417;
48255 con->keep_alive = 0;
48258 array_insert_unique(con->request.headers, (data_unset *)ds);
48260 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
48261 @@ -875,14 +879,15 @@
48263 con->http_status = 400;
48264 con->keep_alive = 0;
48267 if (srv->srvconf.log_request_header_on_error) {
48268 - log_error_write(srv, __FILE__, __LINE__, "s",
48269 + log_error_write(srv, __FILE__, __LINE__, "s",
48270 "duplicate Host-header -> 400");
48271 log_error_write(srv, __FILE__, __LINE__, "Sb",
48272 "request-header:\n",
48273 con->request.request);
48275 + ds->free((data_unset *) ds);
48278 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
48279 @@ -897,14 +902,15 @@
48281 con->http_status = 400;
48282 con->keep_alive = 0;
48285 if (srv->srvconf.log_request_header_on_error) {
48286 - log_error_write(srv, __FILE__, __LINE__, "s",
48287 + log_error_write(srv, __FILE__, __LINE__, "s",
48288 "duplicate If-Modified-Since header -> 400");
48289 log_error_write(srv, __FILE__, __LINE__, "Sb",
48290 "request-header:\n",
48291 con->request.request);
48293 + ds->free((data_unset *) ds);
48296 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
48297 @@ -914,47 +920,49 @@
48299 con->http_status = 400;
48300 con->keep_alive = 0;
48303 if (srv->srvconf.log_request_header_on_error) {
48304 - log_error_write(srv, __FILE__, __LINE__, "s",
48305 + log_error_write(srv, __FILE__, __LINE__, "s",
48306 "duplicate If-None-Match-header -> 400");
48307 log_error_write(srv, __FILE__, __LINE__, "Sb",
48308 "request-header:\n",
48309 con->request.request);
48311 + ds->free((data_unset *) ds);
48314 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
48315 if (!con->request.http_range) {
48319 if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) &&
48320 NULL != strchr(ds->value->ptr+6, '-')) {
48323 /* if dup, only the first one will survive */
48324 con->request.http_range = ds->value->ptr + 6;
48327 con->http_status = 400;
48328 con->keep_alive = 0;
48331 if (srv->srvconf.log_request_header_on_error) {
48332 - log_error_write(srv, __FILE__, __LINE__, "s",
48333 + log_error_write(srv, __FILE__, __LINE__, "s",
48334 "duplicate Range-header -> 400");
48335 log_error_write(srv, __FILE__, __LINE__, "Sb",
48336 "request-header:\n",
48337 con->request.request);
48339 + ds->free((data_unset *) ds);
48345 array_insert_unique(con->request.headers, (data_unset *)ds);
48347 /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
48355 @@ -963,10 +971,10 @@
48358 if (srv->srvconf.log_request_header_on_error) {
48359 - log_error_write(srv, __FILE__, __LINE__, "sbs",
48360 + log_error_write(srv, __FILE__, __LINE__, "sbs",
48361 "CR without LF", con->request.request, "-> 400");
48365 con->http_status = 400;
48366 con->keep_alive = 0;
48367 con->response.keep_alive = 0;
48368 @@ -982,28 +990,28 @@
48374 con->header_len = i;
48377 /* do some post-processing */
48379 if (con->request.http_version == HTTP_VERSION_1_1) {
48380 if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
48381 /* no Connection-Header sent */
48384 /* HTTP/1.1 -> keep-alive default TRUE */
48385 con->keep_alive = 1;
48387 con->keep_alive = 0;
48391 /* RFC 2616, 14.23 */
48392 if (con->request.http_host == NULL ||
48393 buffer_is_empty(con->request.http_host)) {
48394 con->http_status = 400;
48395 con->response.keep_alive = 0;
48396 con->keep_alive = 0;
48399 if (srv->srvconf.log_request_header_on_error) {
48400 log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
48401 log_error_write(srv, __FILE__, __LINE__, "Sb",
48402 @@ -1015,18 +1023,18 @@
48404 if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
48405 /* no Connection-Header sent */
48408 /* HTTP/1.0 -> keep-alive default FALSE */
48409 con->keep_alive = 1;
48411 con->keep_alive = 0;
48416 /* check hostname field if it is set */
48417 if (NULL != con->request.http_host &&
48418 0 != request_check_hostname(srv, con, con->request.http_host)) {
48421 if (srv->srvconf.log_request_header_on_error) {
48422 log_error_write(srv, __FILE__, __LINE__, "s",
48423 "Invalid Hostname -> 400");
48424 @@ -1038,7 +1046,7 @@
48425 con->http_status = 400;
48426 con->response.keep_alive = 0;
48427 con->keep_alive = 0;
48433 @@ -1048,7 +1056,7 @@
48434 /* content-length is forbidden for those */
48435 if (con_length_set && con->request.content_length != 0) {
48436 /* content-length is missing */
48437 - log_error_write(srv, __FILE__, __LINE__, "s",
48438 + log_error_write(srv, __FILE__, __LINE__, "s",
48439 "GET/HEAD with content-length -> 400");
48441 con->keep_alive = 0;
48442 @@ -1060,7 +1068,7 @@
48443 /* content-length is required for them */
48444 if (!con_length_set) {
48445 /* content-length is missing */
48446 - log_error_write(srv, __FILE__, __LINE__, "s",
48447 + log_error_write(srv, __FILE__, __LINE__, "s",
48448 "POST-request, but content-length missing -> 411");
48450 con->keep_alive = 0;
48451 @@ -1073,16 +1081,16 @@
48452 /* the may have a content-length */
48459 /* check if we have read post data */
48460 if (con_length_set) {
48461 /* don't handle more the SSIZE_MAX bytes in content-length */
48462 if (con->request.content_length > SSIZE_MAX) {
48463 - con->http_status = 413;
48464 + con->http_status = 413;
48465 con->keep_alive = 0;
48467 - log_error_write(srv, __FILE__, __LINE__, "sds",
48468 + log_error_write(srv, __FILE__, __LINE__, "sds",
48469 "request-size too long:", con->request.content_length, "-> 413");
48472 @@ -1090,25 +1098,25 @@
48473 /* divide by 1024 as srvconf.max_request_size is in kBytes */
48474 if (srv->srvconf.max_request_size != 0 &&
48475 (con->request.content_length >> 10) > srv->srvconf.max_request_size) {
48476 - /* the request body itself is larger then
48477 + /* the request body itself is larger then
48478 * our our max_request_size
48482 con->http_status = 413;
48483 con->keep_alive = 0;
48485 - log_error_write(srv, __FILE__, __LINE__, "sds",
48487 + log_error_write(srv, __FILE__, __LINE__, "sds",
48488 "request-size too long:", con->request.content_length, "-> 413");
48495 /* we have content */
48496 if (con->request.content_length != 0) {
48505 @@ -1116,9 +1124,9 @@
48508 if (con->request.request->used < 5) return 0;
48511 if (0 == memcmp(con->request.request->ptr + con->request.request->used - 5, "\r\n\r\n", 4)) return 1;
48512 if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1;
48517 --- ../lighttpd-1.4.11/src/response.c 2006-03-04 16:41:39.000000000 +0200
48518 +++ lighttpd-1.4.12/src/response.c 2006-07-16 00:26:04.000000000 +0300
48520 #include <stdlib.h>
48521 #include <string.h>
48523 -#include <unistd.h>
48525 #include <assert.h>
48527 @@ -24,15 +23,17 @@
48528 #include "plugin.h"
48530 #include "sys-socket.h"
48531 +#include "sys-files.h"
48532 +#include "sys-strings.h"
48534 int http_response_write_header(server *srv, connection *con) {
48538 int have_server = 0;
48541 b = chunkqueue_get_prepend_buffer(con->write_queue);
48544 if (con->request.http_version == HTTP_VERSION_1_1) {
48545 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
48547 @@ -41,25 +42,26 @@
48548 buffer_append_long(b, con->http_status);
48549 BUFFER_APPEND_STRING_CONST(b, " ");
48550 buffer_append_string(b, get_http_status_name(con->http_status));
48553 if (con->request.http_version != HTTP_VERSION_1_1 || con->keep_alive == 0) {
48554 BUFFER_APPEND_STRING_CONST(b, "\r\nConnection: ");
48555 buffer_append_string(b, con->keep_alive ? "keep-alive" : "close");
48559 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
48560 BUFFER_APPEND_STRING_CONST(b, "\r\nTransfer-Encoding: chunked");
48566 /* add all headers */
48567 for (i = 0; i < con->response.headers->used; i++) {
48571 ds = (data_string *)con->response.headers->data[i];
48574 if (ds->value->used && ds->key->used &&
48575 - 0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1)) {
48576 + 0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1) &&
48577 + 0 != strcasecmp(ds->key->ptr, "X-Sendfile")) {
48578 if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Date"))) have_date = 1;
48579 if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Server"))) have_server = 1;
48581 @@ -68,28 +70,28 @@
48582 BUFFER_APPEND_STRING_CONST(b, ": ");
48583 buffer_append_string_buffer(b, ds->value);
48585 - log_error_write(srv, __FILE__, __LINE__, "bb",
48586 + log_error_write(srv, __FILE__, __LINE__, "bb",
48587 ds->key, ds->value);
48594 /* HTTP/1.1 requires a Date: header */
48595 BUFFER_APPEND_STRING_CONST(b, "\r\nDate: ");
48598 /* cache the generated timestamp */
48599 if (srv->cur_ts != srv->last_generated_date_ts) {
48600 buffer_prepare_copy(srv->ts_date_str, 255);
48602 - strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
48604 + strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
48605 "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts)));
48608 srv->ts_date_str->used = strlen(srv->ts_date_str->ptr) + 1;
48611 srv->last_generated_date_ts = srv->cur_ts;
48615 buffer_append_string_buffer(b, srv->ts_date_str);
48618 @@ -101,16 +103,16 @@
48619 buffer_append_string_buffer(b, con->conf.server_tag);
48624 BUFFER_APPEND_STRING_CONST(b, "\r\n\r\n");
48629 con->bytes_header = b->used - 1;
48632 if (con->conf.log_response_header) {
48633 log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b);
48640 @@ -118,71 +120,71 @@
48642 handler_t http_response_prepare(server *srv, connection *con) {
48645 - /* looks like someone has already done a decision */
48646 - if (con->mode == DIRECT &&
48648 + /* looks like someone has already made a decision */
48649 + if (con->mode == DIRECT &&
48650 (con->http_status != 0 && con->http_status != 200)) {
48651 /* remove a packets in the queue */
48652 if (con->file_finished == 0) {
48653 chunkqueue_reset(con->write_queue);
48657 return HANDLER_FINISHED;
48661 /* no decision yet, build conf->filename */
48662 if (con->mode == DIRECT && con->physical.path->used == 0) {
48665 - /* we only come here when we have the parse the full request again
48667 - * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
48668 + /* we only come here when we have to parse the full request again
48670 + * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
48671 * problem here as mod_setenv might get called multiple times
48673 * fastcgi-auth might lead to a COMEBACK too
48674 * fastcgi again dead server too
48676 * mod_compress might add headers twice too
48682 if (con->conf.log_condition_handling) {
48683 log_error_write(srv, __FILE__, __LINE__, "s", "run condition");
48685 config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */
48694 * - uri.path (secure)
48703 * Name according to RFC 2396
48712 * (scheme)://(authority)(path)?(query)
48720 buffer_copy_string(con->uri.scheme, con->conf.is_ssl ? "https" : "http");
48721 buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
48722 buffer_to_lower(con->uri.authority);
48725 config_patch_connection(srv, con, COMP_HTTP_HOST); /* Host: */
48726 config_patch_connection(srv, con, COMP_HTTP_REMOTEIP); /* Client-IP */
48727 config_patch_connection(srv, con, COMP_HTTP_REFERER); /* Referer: */
48728 config_patch_connection(srv, con, COMP_HTTP_USERAGENT); /* User-Agent: */
48729 config_patch_connection(srv, con, COMP_HTTP_COOKIE); /* Cookie: */
48732 /** extract query string from request.uri */
48733 if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) {
48734 buffer_copy_string (con->uri.query, qstr + 1);
48735 @@ -200,22 +202,22 @@
48736 log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path : ", con->uri.path_raw);
48737 log_error_write(srv, __FILE__, __LINE__, "sb", "URI-query : ", con->uri.query);
48741 /* disable keep-alive if requested */
48744 if (con->request_count > con->conf.max_keep_alive_requests) {
48745 con->keep_alive = 0;
48758 * - based on the raw URL
48764 switch(r = plugins_call_handle_uri_raw(srv, con)) {
48765 case HANDLER_GO_ON:
48767 @@ -229,14 +231,14 @@
48771 - /* build filename
48772 + /* build filename
48774 * - decode url-encodings (e.g. %20 -> ' ')
48775 * - remove path-modifiers (e.g. /../)
48783 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
48784 con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
48785 /* OPTIONS * ... */
48786 @@ -253,15 +255,20 @@
48796 * - based on the clean URL
48802 config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */
48805 + /* do we have to downgrade to 1.0 ? */
48806 + if (!con->conf.allow_http11) {
48807 + con->request.http_version = HTTP_VERSION_1_0;
48810 switch(r = plugins_call_handle_uri_clean(srv, con)) {
48811 case HANDLER_GO_ON:
48813 @@ -274,11 +281,11 @@
48814 log_error_write(srv, __FILE__, __LINE__, "");
48819 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
48820 con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
48821 - /* option requests are handled directly without checking of the path */
48823 + /* option requests are handled directly without checking the path */
48825 response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
48827 con->http_status = 200;
48828 @@ -288,46 +295,47 @@
48838 * logical filename (URI) becomes a physical filename here
48855 * ... ISREG() -> ok, go on
48856 * ... ISDIR() -> index-file -> redirect
48871 * SEARCH DOCUMENT ROOT
48875 /* set a default */
48878 buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root);
48879 buffer_copy_string_buffer(con->physical.rel_path, con->uri.path);
48881 -#if defined(__WIN32) || defined(__CYGWIN__)
48882 - /* strip dots from the end and spaces
48884 + filename_unix2local(con->physical.rel_path);
48885 +#if defined(_WIN32) || defined(__CYGWIN__)
48886 + /* strip dots and spaces from the end
48888 * windows/dos handle those filenames as the same file
48890 * foo == foo. == foo..... == "foo... " == "foo.. ./"
48892 - * This will affect in some cases PATHINFO
48893 + * This will affect PATHINFO in some cases
48895 * on native windows we could prepend the filename with \\?\ to circumvent
48896 * this behaviour. I have no idea how to push this through cygwin
48897 @@ -377,36 +385,41 @@
48898 log_error_write(srv, __FILE__, __LINE__, "");
48902 - /* MacOS X and Windows can't distiguish between upper and lower-case
48904 - * convert to lower-case
48906 + /* The default Mac OS X and Windows filesystems can't distiguish between
48907 + * upper- and lowercase, so convert to lowercase
48909 if (con->conf.force_lowercase_filenames) {
48910 buffer_to_lower(con->physical.rel_path);
48913 - /* the docroot plugins might set the servername, if they don't we take http-host */
48914 + /* the docroot plugins might set the servername; if they don't we take http-host */
48915 if (buffer_is_empty(con->server_name)) {
48916 buffer_copy_string_buffer(con->server_name, con->uri.authority);
48920 - * create physical filename
48923 + * create physical filename
48924 * -> physical.path = docroot + rel_path
48930 buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
48931 - BUFFER_APPEND_SLASH(con->physical.path);
48932 + PATHNAME_APPEND_SLASH(con->physical.path);
48933 buffer_copy_string_buffer(con->physical.basedir, con->physical.path);
48934 if (con->physical.rel_path->used &&
48935 - con->physical.rel_path->ptr[0] == '/') {
48936 + con->physical.rel_path->ptr[0] == DIR_SEPERATOR) {
48937 buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2);
48939 buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
48942 + /* win32: directories can't have a trailing slash */
48943 + if (con->physical.path->ptr[con->physical.path->used - 2] == DIR_SEPERATOR) {
48944 + con->physical.path->ptr[con->physical.path->used - 2] = '\0';
48945 + con->physical.path->used--;
48948 if (con->conf.log_request_handling) {
48949 log_error_write(srv, __FILE__, __LINE__, "s", "-- after doc_root");
48950 log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root);
48951 @@ -426,7 +439,7 @@
48952 log_error_write(srv, __FILE__, __LINE__, "");
48957 if (con->conf.log_request_handling) {
48958 log_error_write(srv, __FILE__, __LINE__, "s", "-- logical -> physical");
48959 log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root);
48960 @@ -434,38 +447,38 @@
48961 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
48966 - * Noone catched away the file from normal path of execution yet (like mod_access)
48970 + * No one took the file away from the normal path of execution yet (like mod_access)
48972 * Go on and check of the file exists at all
48976 if (con->mode == DIRECT) {
48977 char *slash = NULL;
48978 char *pathinfo = NULL;
48980 stat_cache_entry *sce = NULL;
48983 if (con->conf.log_request_handling) {
48984 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling physical path");
48985 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
48989 if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
48993 if (con->conf.log_request_handling) {
48994 log_error_write(srv, __FILE__, __LINE__, "s", "-- file found");
48995 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
48999 if (S_ISDIR(sce->st.st_mode)) {
49000 - if (con->physical.path->ptr[con->physical.path->used - 2] != '/') {
49001 + if (con->uri.path->ptr[con->uri.path->used - 2] != '/') {
49002 /* redirect to .../ */
49005 http_response_redirect_to_directory(srv, con);
49008 return HANDLER_FINISHED;
49010 } else if (!S_ISREG(sce->st.st_mode)) {
49011 @@ -477,12 +490,12 @@
49014 con->http_status = 403;
49017 if (con->conf.log_request_handling) {
49018 log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied");
49019 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
49023 buffer_reset(con->physical.path);
49024 return HANDLER_FINISHED;
49026 @@ -499,77 +512,77 @@
49027 /* PATH_INFO ! :) */
49030 - /* we have no idea what happend. let's tell the user so. */
49031 + /* we have no idea what happened, so tell the user. */
49032 con->http_status = 500;
49033 buffer_reset(con->physical.path);
49036 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
49037 "file not found ... or so: ", strerror(errno),
49039 "->", con->physical.path);
49042 return HANDLER_FINISHED;
49046 /* not found, perhaps PATHINFO */
49049 buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
49057 buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr);
49059 buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
49063 if (0 == stat(con->physical.path->ptr, &(st)) &&
49064 S_ISREG(st.st_mode)) {
49070 if (pathinfo != NULL) {
49073 slash = strrchr(srv->tmp_buf->ptr, '/');
49076 if (pathinfo != NULL) {
49082 if (slash) pathinfo = slash;
49083 } while ((found == 0) && (slash != NULL) && (slash - srv->tmp_buf->ptr > con->physical.basedir->used - 2));
49087 - /* no it really doesn't exists */
49088 + /* no, it really doesn't exists */
49089 con->http_status = 404;
49092 if (con->conf.log_file_not_found) {
49093 log_error_write(srv, __FILE__, __LINE__, "sbsb",
49094 "file not found:", con->uri.path,
49095 "->", con->physical.path);
49099 buffer_reset(con->physical.path);
49102 return HANDLER_FINISHED;
49106 /* we have a PATHINFO */
49108 buffer_copy_string(con->request.pathinfo, pathinfo);
49116 con->uri.path->used -= strlen(pathinfo);
49117 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
49121 if (con->conf.log_request_handling) {
49122 log_error_write(srv, __FILE__, __LINE__, "s", "-- after pathinfo check");
49123 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
49124 @@ -577,12 +590,12 @@
49125 log_error_write(srv, __FILE__, __LINE__, "sb", "Pathinfo :", con->request.pathinfo);
49130 if (con->conf.log_request_handling) {
49131 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling subrequest");
49132 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
49136 /* call the handlers */
49137 switch(r = plugins_call_handle_subrequest_start(srv, con)) {
49138 case HANDLER_GO_ON:
49139 @@ -593,32 +606,32 @@
49140 if (con->conf.log_request_handling) {
49141 log_error_write(srv, __FILE__, __LINE__, "s", "-- subrequest finished");
49144 - /* something strange happend */
49146 + /* something strange happened */
49150 - /* if we are still here, no one wanted the file, status 403 is ok I think */
49153 + /* if we are still here, no one wanted the file; status 403 is ok I think */
49155 if (con->mode == DIRECT) {
49156 con->http_status = 403;
49159 return HANDLER_FINISHED;
49166 switch(r = plugins_call_handle_subrequest(srv, con)) {
49167 case HANDLER_GO_ON:
49168 - /* request was not handled, looks like we are done */
49169 + /* request was not handled; looks like we are done */
49170 return HANDLER_FINISHED;
49171 case HANDLER_FINISHED:
49172 /* request is finished */
49174 - /* something strange happend */
49175 + /* something strange happened */
49181 return HANDLER_COMEBACK;
49183 --- ../lighttpd-1.4.11/src/server.c 2006-03-04 19:12:17.000000000 +0200
49184 +++ lighttpd-1.4.12/src/server.c 2006-07-18 13:03:40.000000000 +0300
49186 #include <sys/types.h>
49187 -#include <sys/time.h>
49188 #include <sys/stat.h>
49190 #include <string.h>
49193 -#include <unistd.h>
49194 #include <stdlib.h>
49196 #include <signal.h>
49198 #include "plugin.h"
49199 #include "joblist.h"
49200 #include "network_backends.h"
49203 +/* use local getopt implementation */
49204 +# undef HAVE_GETOPT_H
49206 #ifdef HAVE_GETOPT_H
49207 #include <getopt.h>
49209 +#include "getopt.h"
49212 #ifdef HAVE_VALGRIND_VALGRIND_H
49214 /* #define USE_ALARM */
49218 +#undef HAVE_SIGNAL
49221 +#include "sys-files.h"
49222 +#include "sys-process.h"
49223 +#include "sys-socket.h"
49225 static volatile sig_atomic_t srv_shutdown = 0;
49226 static volatile sig_atomic_t graceful_shutdown = 0;
49227 +static volatile sig_atomic_t graceful_restart = 0;
49228 static volatile sig_atomic_t handle_sig_alarm = 1;
49229 static volatile sig_atomic_t handle_sig_hup = 0;
49234 case SIGTERM: srv_shutdown = 1; break;
49237 if (graceful_shutdown) srv_shutdown = 1;
49238 - else graceful_shutdown = 1;
49239 + else graceful_shutdown = 1;
49242 case SIGALRM: handle_sig_alarm = 1; break;
49244 static void signal_handler(int sig) {
49246 case SIGTERM: srv_shutdown = 1; break;
49249 if (graceful_shutdown) srv_shutdown = 1;
49250 - else graceful_shutdown = 1;
49251 + else graceful_shutdown = 1;
49254 case SIGALRM: handle_sig_alarm = 1; break;
49255 @@ -110,35 +122,35 @@
49256 signal(SIGTSTP, SIG_IGN);
49258 if (0 != fork()) exit(0);
49261 if (-1 == setsid()) exit(0);
49263 signal(SIGHUP, SIG_IGN);
49265 if (0 != fork()) exit(0);
49268 if (0 != chdir("/")) exit(0);
49272 static server *server_init(void) {
49276 server *srv = calloc(1, sizeof(*srv));
49278 + srv->max_fds = 1024;
49280 srv->x = buffer_init();
49283 CLEAN(response_header);
49284 CLEAN(parse_full_path);
49285 CLEAN(ts_debug_str);
49286 CLEAN(ts_date_str);
49287 - CLEAN(errorlog_buf);
49288 CLEAN(response_range);
49290 srv->empty_string = buffer_init_string("");
49291 CLEAN(cond_check_buf);
49294 CLEAN(srvconf.errorlog_file);
49295 CLEAN(srvconf.groupname);
49296 CLEAN(srvconf.username);
49297 @@ -146,68 +158,63 @@
49298 CLEAN(srvconf.bindhost);
49299 CLEAN(srvconf.event_handler);
49300 CLEAN(srvconf.pid_file);
49303 CLEAN(tmp_chunk_len);
49308 srv->x = array_init();
49311 CLEAN(config_context);
49312 CLEAN(config_touched);
49317 for (i = 0; i < FILE_CACHE_MAX; i++) {
49318 srv->mtime_cache[i].str = buffer_init();
49322 srv->cur_ts = time(NULL);
49323 srv->startup_ts = srv->cur_ts;
49326 srv->conns = calloc(1, sizeof(*srv->conns));
49327 assert(srv->conns);
49330 srv->joblist = calloc(1, sizeof(*srv->joblist));
49331 assert(srv->joblist);
49334 srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue));
49335 assert(srv->fdwaitqueue);
49338 srv->srvconf.modules = array_init();
49339 srv->srvconf.modules_dir = buffer_init_string(LIBRARY_DIR);
49340 srv->srvconf.network_backend = buffer_init();
49341 srv->srvconf.upload_tempdirs = array_init();
49344 - srv->errorlog_fd = -1;
49345 - srv->errorlog_mode = ERRORLOG_STDERR;
49347 srv->split_vals = array_init();
49353 static void server_free(server *srv) {
49357 for (i = 0; i < FILE_CACHE_MAX; i++) {
49358 buffer_free(srv->mtime_cache[i].str);
49363 buffer_free(srv->x);
49366 CLEAN(response_header);
49367 CLEAN(parse_full_path);
49368 CLEAN(ts_debug_str);
49369 CLEAN(ts_date_str);
49370 - CLEAN(errorlog_buf);
49371 CLEAN(response_range);
49373 CLEAN(empty_string);
49374 CLEAN(cond_check_buf);
49377 CLEAN(srvconf.errorlog_file);
49378 CLEAN(srvconf.groupname);
49379 CLEAN(srvconf.username);
49380 @@ -217,7 +224,7 @@
49381 CLEAN(srvconf.pid_file);
49382 CLEAN(srvconf.modules_dir);
49383 CLEAN(srvconf.network_backend);
49386 CLEAN(tmp_chunk_len);
49389 @@ -225,15 +232,15 @@
49390 fdevent_unregister(srv->ev, srv->fd);
49392 fdevent_free(srv->ev);
49398 if (srv->config_storage) {
49399 for (i = 0; i < srv->config_context->used; i++) {
49400 specific_config *s = srv->config_storage[i];
49405 buffer_free(s->document_root);
49406 buffer_free(s->server_name);
49407 buffer_free(s->server_tag);
49408 @@ -242,32 +249,32 @@
49409 buffer_free(s->error_handler);
49410 buffer_free(s->errorfile_prefix);
49411 array_free(s->mimetypes);
49416 free(srv->config_storage);
49417 srv->config_storage = NULL;
49422 array_free(srv->x);
49425 CLEAN(config_context);
49426 CLEAN(config_touched);
49428 CLEAN(srvconf.upload_tempdirs);
49432 joblist_free(srv, srv->joblist);
49433 fdwaitqueue_free(srv, srv->fdwaitqueue);
49436 if (srv->stat_cache) {
49437 stat_cache_free(srv->stat_cache);
49440 array_free(srv->srvconf.modules);
49441 array_free(srv->split_vals);
49447 @@ -281,14 +288,12 @@
49448 " - a light and fast webserver\n" \
49449 "Build-Date: " __DATE__ " " __TIME__ "\n";
49453 write(STDOUT_FILENO, b, strlen(b));
49456 static void show_features (void) {
49458 - printf("\nEvent Handlers:\n\n%s",
49460 + const char *s = ""
49462 "\t+ select (generic)\n"
49464 @@ -355,11 +360,6 @@
49466 "\t- crypt support\n"
49469 - "\t+ PAM support\n"
49471 - "\t- PAM support\n"
49474 "\t+ SSL Support\n"
49476 @@ -371,9 +371,9 @@
49477 "\t- PCRE support\n"
49480 - "\t+ mySQL support\n"
49481 + "\t+ MySQL support\n"
49483 - "\t- mySQL support\n"
49484 + "\t- MySQL support\n"
49486 #if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
49487 "\t+ LDAP support\n"
49488 @@ -410,8 +410,11 @@
49490 "\t- GDBM support\n"
49498 + printf("\nEvent Handlers:\n\n%s", s);
49501 static void show_help (void) {
49502 @@ -433,277 +436,644 @@
49503 " -h show this help\n" \
49509 write(STDOUT_FILENO, b, strlen(b));
49512 -int main (int argc, char **argv) {
49513 - server *srv = NULL;
49514 - int print_config = 0;
49515 - int test_config = 0;
49518 - int num_childs = 0;
49519 - int pid_fd = -1, fd;
49521 -#ifdef HAVE_SIGACTION
49522 - struct sigaction act;
49524 -#ifdef HAVE_GETRLIMIT
49525 - struct rlimit rlim;
49529 - struct itimerval interval;
49531 - interval.it_interval.tv_sec = 1;
49532 - interval.it_interval.tv_usec = 0;
49533 - interval.it_value.tv_sec = 1;
49534 - interval.it_value.tv_usec = 0;
49538 - /* for nice %b handling in strfime() */
49539 - setlocale(LC_TIME, "C");
49541 - if (NULL == (srv = server_init())) {
49542 - fprintf(stderr, "did this really happen?\n");
49546 - /* init structs done */
49548 - srv->srvconf.port = 0;
49549 -#ifdef HAVE_GETUID
49550 - i_am_root = (getuid() == 0);
49554 - srv->srvconf.dont_daemonize = 0;
49556 - while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
49559 - if (config_read(srv, optarg)) {
49560 - server_free(srv);
49565 - buffer_copy_string(srv->srvconf.modules_dir, optarg);
49567 - case 'p': print_config = 1; break;
49568 - case 't': test_config = 1; break;
49569 - case 'D': srv->srvconf.dont_daemonize = 1; break;
49570 - case 'v': show_version(); return 0;
49571 - case 'V': show_features(); return 0;
49572 - case 'h': show_help(); return 0;
49575 - server_free(srv);
49580 - if (!srv->config_storage) {
49581 - log_error_write(srv, __FILE__, __LINE__, "s",
49582 - "No configuration available. Try using -f option.");
49584 - server_free(srv);
49588 - if (print_config) {
49589 - data_unset *dc = srv->config_context->data[0];
49591 - dc->print(dc, 0);
49592 - fprintf(stderr, "\n");
49594 - /* shouldn't happend */
49595 - fprintf(stderr, "global config not found\n");
49598 +int lighty_mainloop(server *srv) {
49599 + fdevent_revents *revents = fdevent_revents_init();
49601 - if (test_config) {
49602 - printf("Syntax OK\n");
49605 + while (!srv_shutdown) {
49610 - if (test_config || print_config) {
49611 - server_free(srv);
49615 - /* close stdin and stdout, as they are not needed */
49616 - /* move stdin to /dev/null */
49617 - if (-1 != (fd = open("/dev/null", O_RDONLY))) {
49618 - close(STDIN_FILENO);
49619 - dup2(fd, STDIN_FILENO);
49623 - /* move stdout to /dev/null */
49624 - if (-1 != (fd = open("/dev/null", O_WRONLY))) {
49625 - close(STDOUT_FILENO);
49626 - dup2(fd, STDOUT_FILENO);
49630 - if (0 != config_set_defaults(srv)) {
49631 - log_error_write(srv, __FILE__, __LINE__, "s",
49632 - "setting default values failed");
49633 - server_free(srv);
49637 - /* UID handling */
49638 -#ifdef HAVE_GETUID
49639 - if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
49640 - /* we are setuid-root */
49642 - log_error_write(srv, __FILE__, __LINE__, "s",
49643 - "Are you nuts ? Don't apply a SUID bit to this binary");
49645 - server_free(srv);
49650 - /* check document-root */
49651 - if (srv->config_storage[0]->document_root->used <= 1) {
49652 - log_error_write(srv, __FILE__, __LINE__, "s",
49653 - "document-root is not set\n");
49655 - server_free(srv);
49660 - if (plugins_load(srv)) {
49661 - log_error_write(srv, __FILE__, __LINE__, "s",
49662 - "loading plugins finally failed");
49664 - plugins_free(srv);
49665 - server_free(srv);
49670 - /* open pid file BEFORE chroot */
49671 - if (srv->srvconf.pid_file->used) {
49672 - 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))) {
49674 - if (errno != EEXIST) {
49675 - log_error_write(srv, __FILE__, __LINE__, "sbs",
49676 - "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49680 - if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
49681 - log_error_write(srv, __FILE__, __LINE__, "sbs",
49682 - "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49685 - if (!S_ISREG(st.st_mode)) {
49686 - log_error_write(srv, __FILE__, __LINE__, "sb",
49687 - "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
49691 - if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
49692 - log_error_write(srv, __FILE__, __LINE__, "sbs",
49693 - "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49695 + if (handle_sig_hup) {
49698 + /* reset notification */
49699 + handle_sig_hup = 0;
49704 + /* send the old process into a graceful-shutdown and start a
49705 + * new process right away
49708 + * - if webserver is running on port < 1024 (e.g. 80, 433)
49709 + * we don't have the permissions to bind to that port anymore
49713 + if (0 == (pid = fork())) {
49714 + execve(argv[0], argv, envp);
49717 + } else if (pid == -1) {
49722 + graceful_shutdown = 1; /* shutdown without killing running connections */
49723 + graceful_restart = 1; /* don't delete pid file */
49728 + /* cycle logfiles */
49730 - if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
49731 - /* select limits itself
49733 - * as it is a hard limit and will lead to a segfault we add some safety
49735 - srv->max_fds = FD_SETSIZE - 200;
49737 - srv->max_fds = 4096;
49739 + switch(r = plugins_call_handle_sighup(srv)) {
49740 + case HANDLER_GO_ON:
49743 + log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
49748 - struct group *grp = NULL;
49749 - struct passwd *pwd = NULL;
49750 - int use_rlimit = 1;
49751 + if (-1 == log_error_cycle()) {
49752 + log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
49754 -#ifdef HAVE_VALGRIND_VALGRIND_H
49755 - if (RUNNING_ON_VALGRIND) use_rlimit = 0;
49758 -#ifdef HAVE_GETRLIMIT
49759 - if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
49760 - log_error_write(srv, __FILE__, __LINE__,
49761 - "ss", "couldn't get 'max filedescriptors'",
49762 - strerror(errno));
49766 - if (use_rlimit && srv->srvconf.max_fds) {
49767 - /* set rlimits */
49769 - rlim.rlim_cur = srv->srvconf.max_fds;
49770 - rlim.rlim_max = srv->srvconf.max_fds;
49772 - if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
49773 - log_error_write(srv, __FILE__, __LINE__,
49774 - "ss", "couldn't set 'max filedescriptors'",
49775 - strerror(errno));
49781 - /* #372: solaris need some fds extra for devpoll */
49782 - if (rlim.rlim_cur > 10) rlim.rlim_cur -= 10;
49783 + if (handle_sig_alarm) {
49784 + /* a new second */
49786 - if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
49787 - srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
49789 - srv->max_fds = rlim.rlim_cur;
49792 + /* reset notification */
49793 + handle_sig_alarm = 0;
49796 - /* set core file rlimit, if enable_cores is set */
49797 - if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
49798 - rlim.rlim_cur = rlim.rlim_max;
49799 + /* get current time */
49800 + min_ts = time(NULL);
49802 + if (min_ts != srv->cur_ts) {
49804 + connections *conns = srv->conns;
49807 + switch(r = plugins_call_handle_trigger(srv)) {
49808 + case HANDLER_GO_ON:
49810 + case HANDLER_ERROR:
49811 + log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
49814 + log_error_write(srv, __FILE__, __LINE__, "d", r);
49818 + /* trigger waitpid */
49819 + srv->cur_ts = min_ts;
49821 + /* cleanup stat-cache */
49822 + stat_cache_trigger_cleanup(srv);
49824 + * check all connections for timeouts
49827 + for (ndx = 0; ndx < conns->used; ndx++) {
49832 + con = conns->ptr[ndx];
49834 + if (con->state == CON_STATE_READ ||
49835 + con->state == CON_STATE_READ_POST) {
49836 + if (con->request_count == 1) {
49837 + if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
49840 + log_error_write(srv, __FILE__, __LINE__, "sd",
49841 + "connection closed - read-timeout:", con->fd);
49843 + connection_set_state(srv, con, CON_STATE_ERROR);
49847 + if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
49850 + log_error_write(srv, __FILE__, __LINE__, "sd",
49851 + "connection closed - read-timeout:", con->fd);
49853 + connection_set_state(srv, con, CON_STATE_ERROR);
49859 + if ((con->state == CON_STATE_WRITE) &&
49860 + (con->write_request_ts != 0)) {
49862 + if (srv->cur_ts - con->write_request_ts > 60) {
49863 + log_error_write(srv, __FILE__, __LINE__, "sdd",
49864 + "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
49868 + if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
49871 + log_error_write(srv, __FILE__, __LINE__, "sbsosds",
49872 + "NOTE: a request for",
49873 + con->request.uri,
49874 + "timed out after writing",
49875 + con->bytes_written,
49876 + "bytes. We waited",
49877 + (int)con->conf.max_write_idle,
49878 + "seconds. If this a problem increase server.max-write-idle");
49880 + connection_set_state(srv, con, CON_STATE_ERROR);
49884 + /* we don't like div by zero */
49885 + if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
49887 + if (con->traffic_limit_reached &&
49888 + (con->conf.kbytes_per_second == 0 ||
49889 + ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
49890 + /* enable connection again */
49891 + con->traffic_limit_reached = 0;
49897 + connection_state_machine(srv, con);
49899 + con->bytes_written_cur_second = 0;
49900 + *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
49904 + fprintf(stderr, "connection-state: ");
49908 + fprintf(stderr, "c[%d,%d]: %s ",
49911 + connection_get_state(con->state));
49915 + if (cs == 1) fprintf(stderr, "\n");
49919 + if (srv->sockets_disabled) {
49920 + /* our server sockets are disabled, why ? */
49922 + if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
49923 + (srv->conns->used < srv->max_conns * 0.9) &&
49924 + (0 == graceful_shutdown)) {
49927 + for (i = 0; i < srv->srv_sockets.used; i++) {
49928 + server_socket *srv_socket = srv->srv_sockets.ptr[i];
49929 + fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
49932 + log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
49934 + srv->sockets_disabled = 0;
49937 + if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
49938 + (srv->conns->used > srv->max_conns) || /* out of connections */
49939 + (graceful_shutdown)) { /* graceful_shutdown */
49942 + /* disable server-fds */
49944 + for (i = 0; i < srv->srv_sockets.used; i++) {
49945 + server_socket *srv_socket = srv->srv_sockets.ptr[i];
49946 + fdevent_event_del(srv->ev, srv_socket->sock);
49948 + if (graceful_shutdown) {
49949 + /* we don't want this socket anymore,
49951 + * closing it right away will make it possible for
49952 + * the next lighttpd to take over (graceful restart)
49955 + fdevent_unregister(srv->ev, srv_socket->sock);
49956 + closesocket(srv_socket->sock->fd);
49957 + srv_socket->sock->fd = -1;
49959 + /* network_close() will cleanup after us */
49963 + if (graceful_shutdown) {
49964 + log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
49965 + } else if (srv->conns->used > srv->max_conns) {
49966 + log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
49968 + log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
49971 + srv->sockets_disabled = 1;
49975 + if (graceful_shutdown && srv->conns->used == 0) {
49976 + /* we are in graceful shutdown phase and all connections are closed
49977 + * we are ready to terminate without harming anyone */
49978 + srv_shutdown = 1;
49981 + /* we still have some fds to share */
49982 + if (srv->want_fds) {
49983 + /* check the fdwaitqueue for waiting fds */
49984 + int free_fds = srv->max_fds - srv->cur_fds - 16;
49987 + for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
49988 + connection_state_machine(srv, con);
49994 + if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
49995 + /* n is the number of events */
49997 + fdevent_get_revents(srv->ev, n, revents);
49999 + /* handle client connections first
50001 + * this is a bit of a hack, but we have to make sure than we handle
50002 + * close-events before the connection is reused for a keep-alive
50005 + * this is mostly an issue for mod_proxy_core, but you never know
50009 + for (i = 0; i < revents->used; i++) {
50010 + fdevent_revent *revent = revents->ptr[i];
50013 + /* skip server-fds */
50014 + if (revent->handler == network_server_handle_fdevent) continue;
50016 + switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
50017 + case HANDLER_FINISHED:
50018 + case HANDLER_GO_ON:
50019 + case HANDLER_WAIT_FOR_EVENT:
50020 + case HANDLER_WAIT_FOR_FD:
50022 + case HANDLER_ERROR:
50023 + /* should never happen */
50027 + log_error_write(srv, __FILE__, __LINE__, "d", r);
50032 + for (i = 0; i < revents->used; i++) {
50033 + fdevent_revent *revent = revents->ptr[i];
50036 + /* server fds only */
50037 + if (revent->handler != network_server_handle_fdevent) continue;
50039 + switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
50040 + case HANDLER_FINISHED:
50041 + case HANDLER_GO_ON:
50042 + case HANDLER_WAIT_FOR_EVENT:
50043 + case HANDLER_WAIT_FOR_FD:
50045 + case HANDLER_ERROR:
50046 + /* should never happen */
50050 + log_error_write(srv, __FILE__, __LINE__, "d", r);
50055 + } else if (n < 0 && errno != EINTR) {
50056 + log_error_write(srv, __FILE__, __LINE__, "ss",
50057 + "fdevent_poll failed:",
50058 + strerror(errno));
50061 + for (ndx = 0; ndx < srv->joblist->used; ndx++) {
50062 + connection *con = srv->joblist->ptr[ndx];
50065 + connection_state_machine(srv, con);
50067 + switch(r = plugins_call_handle_joblist(srv, con)) {
50068 + case HANDLER_FINISHED:
50069 + case HANDLER_GO_ON:
50072 + log_error_write(srv, __FILE__, __LINE__, "d", r);
50076 + con->in_joblist = 0;
50079 + srv->joblist->used = 0;
50082 + fdevent_revents_free(revents);
50088 +int main (int argc, char **argv, char **envp) {
50089 + server *srv = NULL;
50090 + int print_config = 0;
50091 + int test_config = 0;
50094 + int num_childs = 0;
50095 + int pid_fd = -1, fd;
50098 + char *optarg = NULL;
50101 +#ifdef HAVE_SIGACTION
50102 + struct sigaction act;
50104 +#ifdef HAVE_GETRLIMIT
50105 + struct rlimit rlim;
50109 + struct itimerval interval;
50111 + interval.it_interval.tv_sec = 1;
50112 + interval.it_interval.tv_usec = 0;
50113 + interval.it_value.tv_sec = 1;
50114 + interval.it_value.tv_usec = 0;
50119 + /* for nice %b handling in strfime() */
50120 + setlocale(LC_TIME, "C");
50122 + if (NULL == (srv = server_init())) {
50123 + fprintf(stderr, "did this really happen?\n");
50127 + /* init structs done */
50129 + srv->srvconf.port = 0;
50130 +#ifdef HAVE_GETUID
50131 + i_am_root = (getuid() == 0);
50135 + srv->srvconf.dont_daemonize = 0;
50137 + while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
50141 + /* evil HACK for windows, optarg is not set */
50142 + optarg = argv[optind-1];
50144 + if (config_read(srv, optarg)) {
50145 + server_free(srv);
50151 + buffer_copy_string(srv->srvconf.modules_dir, optarg);
50153 + case 'p': print_config = 1; break;
50154 + case 't': test_config = 1; break;
50155 + case 'D': srv->srvconf.dont_daemonize = 1; break;
50156 + case 'v': show_version(); return 0;
50157 + case 'V': show_features(); return 0;
50158 + case 'h': show_help(); return 0;
50161 + server_free(srv);
50166 + if (!srv->config_storage) {
50167 + log_error_write(srv, __FILE__, __LINE__, "s",
50168 + "No configuration available. Try using -f option.");
50170 + server_free(srv);
50174 + if (print_config) {
50175 + data_unset *dc = srv->config_context->data[0];
50177 + dc->print(dc, 0);
50178 + fprintf(stderr, "\n");
50180 + /* shouldn't happend */
50181 + fprintf(stderr, "global config not found\n");
50185 + if (test_config) {
50186 + printf("Syntax OK\n");
50189 + if (test_config || print_config) {
50190 + server_free(srv);
50194 + /* close stdin and stdout, as they are not needed */
50195 + /* move stdin to /dev/null */
50196 + if (-1 != (fd = open("/dev/null", O_RDONLY))) {
50197 + close(STDIN_FILENO);
50198 + dup2(fd, STDIN_FILENO);
50202 + /* move stdout to /dev/null */
50203 + if (-1 != (fd = open("/dev/null", O_WRONLY))) {
50204 + close(STDOUT_FILENO);
50205 + dup2(fd, STDOUT_FILENO);
50209 + if (0 != config_set_defaults(srv)) {
50210 + log_error_write(srv, __FILE__, __LINE__, "s",
50211 + "setting default values failed");
50212 + server_free(srv);
50216 + /* UID handling */
50217 +#ifdef HAVE_GETUID
50218 + if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
50219 + /* we are setuid-root */
50221 + log_error_write(srv, __FILE__, __LINE__, "s",
50222 + "Are you nuts ? Don't apply a SUID bit to this binary");
50224 + server_free(srv);
50229 + /* check document-root */
50230 + if (srv->config_storage[0]->document_root->used <= 1) {
50231 + log_error_write(srv, __FILE__, __LINE__, "s",
50232 + "document-root is not set\n");
50234 + server_free(srv);
50239 + if (plugins_load(srv)) {
50240 + log_error_write(srv, __FILE__, __LINE__, "s",
50241 + "loading plugins finally failed");
50243 + plugins_free(srv);
50244 + server_free(srv);
50250 + /* open pid file BEFORE chroot */
50251 + if (srv->srvconf.pid_file->used) {
50252 + 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))) {
50254 + if (errno != EEXIST) {
50255 + log_error_write(srv, __FILE__, __LINE__, "sbs",
50256 + "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
50260 + if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
50261 + log_error_write(srv, __FILE__, __LINE__, "sbs",
50262 + "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
50265 + if (!S_ISREG(st.st_mode)) {
50266 + log_error_write(srv, __FILE__, __LINE__, "sb",
50267 + "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
50271 + if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
50272 + log_error_write(srv, __FILE__, __LINE__, "sbs",
50273 + "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
50279 + if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50280 + /* select limits itself
50282 + * as it is a hard limit and will lead to a segfault we add some safety
50284 + fprintf(stderr, "%s.%d: max parallel connections: %d\r\n", __FILE__, __LINE__, FD_SETSIZE);
50285 + srv->max_fds = FD_SETSIZE - 4;
50287 + srv->max_fds = 4096;
50291 + struct group *grp = NULL;
50292 + struct passwd *pwd = NULL;
50293 + int use_rlimit = 1;
50295 +#ifdef HAVE_VALGRIND_VALGRIND_H
50296 + if (RUNNING_ON_VALGRIND) use_rlimit = 0;
50299 +#ifdef HAVE_GETRLIMIT
50300 + if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
50301 + log_error_write(srv, __FILE__, __LINE__,
50302 + "ss", "couldn't get 'max filedescriptors'",
50303 + strerror(errno));
50307 + if (use_rlimit && srv->srvconf.max_fds) {
50308 + /* set rlimits */
50310 + rlim.rlim_cur = srv->srvconf.max_fds;
50311 + rlim.rlim_max = srv->srvconf.max_fds;
50313 + if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
50314 + log_error_write(srv, __FILE__, __LINE__,
50315 + "ss", "couldn't set 'max filedescriptors'",
50316 + strerror(errno));
50321 + /* #372: solaris need some fds extra for devpoll */
50322 + if (rlim.rlim_cur > 10) rlim.rlim_cur -= 10;
50324 + if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50325 + srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
50327 + srv->max_fds = rlim.rlim_cur;
50330 + /* set core file rlimit, if enable_cores is set */
50331 + if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
50332 + rlim.rlim_cur = rlim.rlim_max;
50333 setrlimit(RLIMIT_CORE, &rlim);
50336 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50337 /* don't raise the limit above FD_SET_SIZE */
50338 if (srv->max_fds > FD_SETSIZE - 200) {
50339 - log_error_write(srv, __FILE__, __LINE__, "sd",
50340 + log_error_write(srv, __FILE__, __LINE__, "sd",
50341 "can't raise max filedescriptors above", FD_SETSIZE - 200,
50342 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
50350 /* set user and group */
50351 if (srv->srvconf.username->used) {
50352 if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) {
50353 - log_error_write(srv, __FILE__, __LINE__, "sb",
50354 + log_error_write(srv, __FILE__, __LINE__, "sb",
50355 "can't find username", srv->srvconf.username);
50360 if (pwd->pw_uid == 0) {
50361 log_error_write(srv, __FILE__, __LINE__, "s",
50362 "I will not set uid to 0\n");
50368 if (srv->srvconf.groupname->used) {
50369 if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) {
50370 - log_error_write(srv, __FILE__, __LINE__, "sb",
50371 + log_error_write(srv, __FILE__, __LINE__, "sb",
50372 "can't find groupname", srv->srvconf.groupname);
50375 @@ -713,15 +1083,15 @@
50381 /* we need root-perms for port < 1024 */
50382 if (0 != network_init(srv)) {
50389 -#ifdef HAVE_CHROOT
50390 +#ifdef HAVE_CHROOT
50391 if (srv->srvconf.changeroot->used) {
50394 @@ -761,7 +1131,7 @@
50397 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50398 - srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
50399 + srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 4 ? rlim.rlim_cur : FD_SETSIZE - 4;
50401 srv->max_fds = rlim.rlim_cur;
50403 @@ -775,18 +1145,18 @@
50405 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50406 /* don't raise the limit above FD_SET_SIZE */
50407 - if (srv->max_fds > FD_SETSIZE - 200) {
50408 - log_error_write(srv, __FILE__, __LINE__, "sd",
50409 - "can't raise max filedescriptors above", FD_SETSIZE - 200,
50410 + if (srv->max_fds > FD_SETSIZE - 4) {
50411 + log_error_write(srv, __FILE__, __LINE__, "sd",
50412 + "can't raise max filedescriptors above", FD_SETSIZE - 4,
50413 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
50419 if (0 != network_init(srv)) {
50427 @@ -802,25 +1172,27 @@
50428 /* or use the default */
50429 srv->max_conns = srv->max_fds;
50433 if (HANDLER_GO_ON != plugins_call_init(srv)) {
50434 log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down.");
50438 network_close(srv);
50447 /* network is up, let's deamonize ourself */
50448 if (srv->srvconf.dont_daemonize == 0) daemonize();
50452 srv->gid = getgid();
50453 srv->uid = getuid();
50457 /* write pid file */
50458 if (pid_fd != -1) {
50459 buffer_copy_long(srv->tmp_buf, getpid());
50460 @@ -829,17 +1201,17 @@
50466 if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) {
50467 log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down.");
50471 network_close(srv);
50479 /* dump unused config-keys */
50480 for (i = 0; i < srv->config_context->used; i++) {
50481 array *config = ((data_config *)srv->config_context->data[i])->value;
50482 @@ -847,43 +1219,42 @@
50484 for (j = 0; config && j < config->used; j++) {
50485 data_unset *du = config->data[j];
50488 /* all var.* is known as user defined variable */
50489 if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) {
50493 if (NULL == array_get_element(srv->config_touched, du->key->ptr)) {
50494 - log_error_write(srv, __FILE__, __LINE__, "sbs",
50495 + log_error_write(srv, __FILE__, __LINE__, "sbs",
50496 "WARNING: unknown config-key:",
50504 if (srv->config_deprecated) {
50505 - log_error_write(srv, __FILE__, __LINE__, "s",
50506 + log_error_write(srv, __FILE__, __LINE__, "s",
50507 "Configuration contains deprecated keys. Going down.");
50511 network_close(srv);
50518 - if (-1 == log_error_open(srv)) {
50519 - log_error_write(srv, __FILE__, __LINE__, "s",
50521 + if (-1 == log_error_open(srv->srvconf.errorlog_file, srv->srvconf.errorlog_use_syslog)) {
50522 + log_error_write(srv, __FILE__, __LINE__, "s",
50523 "opening errorlog failed, dying");
50527 network_close(srv);
50534 #ifdef HAVE_SIGACTION
50535 memset(&act, 0, sizeof(act));
50536 act.sa_handler = SIG_IGN;
50537 @@ -903,7 +1274,7 @@
50538 sigaction(SIGHUP, &act, NULL);
50539 sigaction(SIGALRM, &act, NULL);
50540 sigaction(SIGCHLD, &act, NULL);
50543 #elif defined(HAVE_SIGNAL)
50544 /* ignore the SIGPIPE from sendfile() */
50545 signal(SIGPIPE, SIG_IGN);
50546 @@ -914,20 +1285,20 @@
50547 signal(SIGCHLD, signal_handler);
50548 signal(SIGINT, signal_handler);
50553 signal(SIGALRM, signal_handler);
50556 /* setup periodic timer (1 second) */
50557 if (setitimer(ITIMER_REAL, &interval, NULL)) {
50558 log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed");
50563 getitimer(ITIMER_REAL, &interval);
50568 /* start watcher and workers */
50569 num_childs = srv->srvconf.max_worker;
50570 if (num_childs > 0) {
50571 @@ -957,13 +1328,13 @@
50575 - if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) {
50576 + if (NULL == (srv->ev = fdevent_init(/*srv->max_fds + 1*/ 4096, srv->event_handler))) {
50577 log_error_write(srv, __FILE__, __LINE__,
50578 "s", "fdevent_init failed");
50582 - * kqueue() is called here, select resets its internals,
50584 + * kqueue() is called here, select resets its internals,
50585 * all server sockets get their handlers
50588 @@ -971,7 +1342,7 @@
50590 network_close(srv);
50597 @@ -986,17 +1357,17 @@
50599 if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
50600 if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) {
50601 - log_error_write(srv, __FILE__, __LINE__, "s",
50602 + log_error_write(srv, __FILE__, __LINE__, "s",
50603 "could not open a fam connection, dieing.");
50606 #ifdef HAVE_FAMNOEXISTS
50607 FAMNoExists(srv->stat_cache->fam);
50609 + srv->stat_cache->sock->fd = FAMCONNECTION_GETFD(srv->stat_cache->fam);
50611 - srv->stat_cache->fam_fcce_ndx = -1;
50612 - fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL);
50613 - fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN);
50614 + fdevent_register(srv->ev, srv->stat_cache->sock, stat_cache_handle_fdevent, NULL);
50615 + fdevent_event_add(srv->ev, srv->stat_cache->sock, FDEVENT_IN);
50619 @@ -1007,330 +1378,34 @@
50621 for (i = 0; i < srv->srv_sockets.used; i++) {
50622 server_socket *srv_socket = srv->srv_sockets.ptr[i];
50623 - if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) {
50624 + if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->sock)) {
50625 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno));
50631 - while (!srv_shutdown) {
50636 - if (handle_sig_hup) {
50639 - /* reset notification */
50640 - handle_sig_hup = 0;
50643 - /* cycle logfiles */
50645 - switch(r = plugins_call_handle_sighup(srv)) {
50646 - case HANDLER_GO_ON:
50649 - log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
50653 - if (-1 == log_error_cycle(srv)) {
50654 - log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
50660 - if (handle_sig_alarm) {
50661 - /* a new second */
50664 - /* reset notification */
50665 - handle_sig_alarm = 0;
50668 - /* get current time */
50669 - min_ts = time(NULL);
50671 - if (min_ts != srv->cur_ts) {
50673 - connections *conns = srv->conns;
50676 - switch(r = plugins_call_handle_trigger(srv)) {
50677 - case HANDLER_GO_ON:
50679 - case HANDLER_ERROR:
50680 - log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
50683 - log_error_write(srv, __FILE__, __LINE__, "d", r);
50687 - /* trigger waitpid */
50688 - srv->cur_ts = min_ts;
50690 - /* cleanup stat-cache */
50691 - stat_cache_trigger_cleanup(srv);
50693 - * check all connections for timeouts
50696 - for (ndx = 0; ndx < conns->used; ndx++) {
50701 - con = conns->ptr[ndx];
50703 - if (con->state == CON_STATE_READ ||
50704 - con->state == CON_STATE_READ_POST) {
50705 - if (con->request_count == 1) {
50706 - if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
50709 - log_error_write(srv, __FILE__, __LINE__, "sd",
50710 - "connection closed - read-timeout:", con->fd);
50712 - connection_set_state(srv, con, CON_STATE_ERROR);
50716 - if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
50719 - log_error_write(srv, __FILE__, __LINE__, "sd",
50720 - "connection closed - read-timeout:", con->fd);
50722 - connection_set_state(srv, con, CON_STATE_ERROR);
50728 - if ((con->state == CON_STATE_WRITE) &&
50729 - (con->write_request_ts != 0)) {
50731 - if (srv->cur_ts - con->write_request_ts > 60) {
50732 - log_error_write(srv, __FILE__, __LINE__, "sdd",
50733 - "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
50737 - if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
50740 - log_error_write(srv, __FILE__, __LINE__, "sbsosds",
50741 - "NOTE: a request for",
50742 - con->request.uri,
50743 - "timed out after writing",
50744 - con->bytes_written,
50745 - "bytes. We waited",
50746 - (int)con->conf.max_write_idle,
50747 - "seconds. If this a problem increase server.max-write-idle");
50749 - connection_set_state(srv, con, CON_STATE_ERROR);
50753 - /* we don't like div by zero */
50754 - if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
50756 - if (con->traffic_limit_reached &&
50757 - (con->conf.kbytes_per_second == 0 ||
50758 - ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
50759 - /* enable connection again */
50760 - con->traffic_limit_reached = 0;
50766 - connection_state_machine(srv, con);
50768 - con->bytes_written_cur_second = 0;
50769 - *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
50773 - fprintf(stderr, "connection-state: ");
50777 - fprintf(stderr, "c[%d,%d]: %s ",
50780 - connection_get_state(con->state));
50784 - if (cs == 1) fprintf(stderr, "\n");
50788 - if (srv->sockets_disabled) {
50789 - /* our server sockets are disabled, why ? */
50791 - if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
50792 - (srv->conns->used < srv->max_conns * 0.9) &&
50793 - (0 == graceful_shutdown)) {
50794 - for (i = 0; i < srv->srv_sockets.used; i++) {
50795 - server_socket *srv_socket = srv->srv_sockets.ptr[i];
50796 - fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
50799 - log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
50801 - srv->sockets_disabled = 0;
50804 - if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
50805 - (srv->conns->used > srv->max_conns) || /* out of connections */
50806 - (graceful_shutdown)) { /* graceful_shutdown */
50808 - /* disable server-fds */
50810 - for (i = 0; i < srv->srv_sockets.used; i++) {
50811 - server_socket *srv_socket = srv->srv_sockets.ptr[i];
50812 - fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
50814 - if (graceful_shutdown) {
50815 - /* we don't want this socket anymore,
50817 - * closing it right away will make it possible for
50818 - * the next lighttpd to take over (graceful restart)
50821 - fdevent_unregister(srv->ev, srv_socket->fd);
50822 - close(srv_socket->fd);
50823 - srv_socket->fd = -1;
50825 - /* network_close() will cleanup after us */
50829 - if (graceful_shutdown) {
50830 - log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
50831 - } else if (srv->conns->used > srv->max_conns) {
50832 - log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
50834 - log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
50837 - srv->sockets_disabled = 1;
50841 - if (graceful_shutdown && srv->conns->used == 0) {
50842 - /* we are in graceful shutdown phase and all connections are closed
50843 - * we are ready to terminate without harming anyone */
50844 - srv_shutdown = 1;
50847 - /* we still have some fds to share */
50848 - if (srv->want_fds) {
50849 - /* check the fdwaitqueue for waiting fds */
50850 - int free_fds = srv->max_fds - srv->cur_fds - 16;
50853 - for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
50854 - connection_state_machine(srv, con);
50859 + lighty_mainloop(srv);
50861 - if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
50862 - /* n is the number of events */
50867 - log_error_write(srv, __FILE__, __LINE__, "sd",
50873 - fdevent_handler handler;
50877 - fd_ndx = fdevent_event_next_fdndx (srv->ev, fd_ndx);
50878 - revents = fdevent_event_get_revent (srv->ev, fd_ndx);
50879 - fd = fdevent_event_get_fd (srv->ev, fd_ndx);
50880 - handler = fdevent_get_handler(srv->ev, fd);
50881 - context = fdevent_get_context(srv->ev, fd);
50883 - /* connection_handle_fdevent needs a joblist_append */
50885 - log_error_write(srv, __FILE__, __LINE__, "sdd",
50886 - "event for", fd, revents);
50888 - switch (r = (*handler)(srv, context, revents)) {
50889 - case HANDLER_FINISHED:
50890 - case HANDLER_GO_ON:
50891 - case HANDLER_WAIT_FOR_EVENT:
50892 - case HANDLER_WAIT_FOR_FD:
50894 - case HANDLER_ERROR:
50895 - /* should never happen */
50899 - log_error_write(srv, __FILE__, __LINE__, "d", r);
50902 - } while (--n > 0);
50903 - } else if (n < 0 && errno != EINTR) {
50904 - log_error_write(srv, __FILE__, __LINE__, "ss",
50905 - "fdevent_poll failed:",
50906 - strerror(errno));
50909 - for (ndx = 0; ndx < srv->joblist->used; ndx++) {
50910 - connection *con = srv->joblist->ptr[ndx];
50913 - connection_state_machine(srv, con);
50915 - switch(r = plugins_call_handle_joblist(srv, con)) {
50916 - case HANDLER_FINISHED:
50917 - case HANDLER_GO_ON:
50920 - log_error_write(srv, __FILE__, __LINE__, "d", r);
50924 - con->in_joblist = 0;
50927 - srv->joblist->used = 0;
50930 - if (srv->srvconf.pid_file->used &&
50931 + if (0 == graceful_restart &&
50932 + srv->srvconf.pid_file->used &&
50933 srv->srvconf.changeroot->used == 0) {
50934 if (0 != unlink(srv->srvconf.pid_file->ptr)) {
50935 if (errno != EACCES && errno != EPERM) {
50936 - log_error_write(srv, __FILE__, __LINE__, "sbds",
50937 - "unlink failed for:",
50938 + log_error_write(srv, __FILE__, __LINE__, "sbds",
50939 + "unlink failed for:",
50940 srv->srvconf.pid_file,
50949 - log_error_close(srv);
50950 network_close(srv);
50951 connections_free(srv);
50959 --- ../lighttpd-1.4.11/src/settings.h 2005-08-11 01:26:41.000000000 +0300
50960 +++ lighttpd-1.4.12/src/settings.h 2006-07-16 00:26:04.000000000 +0300
50963 * max size of a buffer which will just be reset
50964 * to ->used = 0 instead of really freeing the buffer
50967 * 64kB (no real reason, just a guess)
50969 #define BUFFER_MAX_REUSE_SIZE (4 * 1024)
50972 * max size of the HTTP request header
50975 * 32k should be enough for everything (just a guess)
50979 #define MAX_HTTP_REQUEST_HEADER (32 * 1024)
50981 -typedef enum { HANDLER_UNSET,
50983 +typedef enum { HANDLER_UNSET,
50986 - HANDLER_COMEBACK,
50987 - HANDLER_WAIT_FOR_EVENT,
50988 + HANDLER_COMEBACK,
50989 + HANDLER_WAIT_FOR_EVENT,
50991 HANDLER_WAIT_FOR_FD
50993 --- ../lighttpd-1.4.11/src/spawn-fcgi.c 2006-03-07 14:18:10.000000000 +0200
50994 +++ lighttpd-1.4.12/src/spawn-fcgi.c 2006-07-16 00:26:04.000000000 +0300
50996 #include <sys/types.h>
50997 -#include <sys/time.h>
50998 #include <sys/stat.h>
51000 #include <stdlib.h>
51001 #include <string.h>
51004 -#include <unistd.h>
51008 #ifdef HAVE_CONFIG_H
51009 #include "config.h"
51019 #include "sys-socket.h"
51020 +#include "sys-files.h"
51022 #ifdef HAVE_SYS_WAIT_H
51023 #include <sys/wait.h>
51024 @@ -45,28 +43,28 @@
51026 int socket_type, status;
51027 struct timeval tv = { 0, 100 * 1000 };
51030 struct sockaddr_un fcgi_addr_un;
51031 struct sockaddr_in fcgi_addr_in;
51032 struct sockaddr *fcgi_addr;
51038 if (child_count < 2) {
51043 if (child_count > 256) {
51051 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
51054 fcgi_addr_un.sun_family = AF_UNIX;
51055 strcpy(fcgi_addr_un.sun_path, unixsocket);
51059 servlen = SUN_LEN(&fcgi_addr_un);
51061 @@ -84,50 +82,50 @@
51063 fcgi_addr_in.sin_port = htons(port);
51064 servlen = sizeof(fcgi_addr_in);
51067 socket_type = AF_INET;
51068 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
51072 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
51073 - fprintf(stderr, "%s.%d\n",
51074 + fprintf(stderr, "%s.%d\n",
51075 __FILE__, __LINE__);
51080 if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
51081 /* server is not up, spawn in */
51086 if (unixsocket) unlink(unixsocket);
51092 /* reopen socket */
51093 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
51094 - fprintf(stderr, "%s.%d\n",
51095 + fprintf(stderr, "%s.%d\n",
51096 __FILE__, __LINE__);
51101 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
51102 - fprintf(stderr, "%s.%d\n",
51103 + fprintf(stderr, "%s.%d\n",
51104 __FILE__, __LINE__);
51108 /* create socket */
51109 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
51110 - fprintf(stderr, "%s.%d: bind failed: %s\n",
51111 + fprintf(stderr, "%s.%d: bind failed: %s\n",
51112 __FILE__, __LINE__,
51118 if (-1 == listen(fcgi_fd, 1024)) {
51119 - fprintf(stderr, "%s.%d: fd = -1\n",
51120 + fprintf(stderr, "%s.%d: fd = -1\n",
51121 __FILE__, __LINE__);
51124 @@ -137,42 +135,45 @@
51132 char cgi_childs[64];
51139 + /* loose control terminal */
51142 /* is save as we limit to 256 childs */
51143 sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count);
51146 if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
51147 close(FCGI_LISTENSOCK_FILENO);
51148 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
51153 /* we don't need the client socket */
51154 for (i = 3; i < 256; i++) {
51159 /* create environment */
51162 putenv(cgi_childs);
51165 /* fork and replace shell */
51166 b = malloc(strlen("exec ") + strlen(appPath) + 1);
51167 strcpy(b, "exec ");
51168 strcat(b, appPath);
51172 execl("/bin/sh", "sh", "-c", b, NULL);
51181 @@ -180,47 +181,47 @@
51188 select(0, NULL, NULL, NULL, &tv);
51191 switch (waitpid(child, &status, WNOHANG)) {
51193 - fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
51194 + fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
51195 __FILE__, __LINE__,
51199 /* write pid file */
51200 if (pid_fd != -1) {
51201 /* assume a 32bit pid_t */
51205 snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child);
51208 write(pid_fd, pidbuf, strlen(pidbuf));
51218 if (WIFEXITED(status)) {
51219 - fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
51220 + fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
51221 __FILE__, __LINE__,
51222 WEXITSTATUS(status), strerror(WEXITSTATUS(status)));
51223 } else if (WIFSIGNALED(status)) {
51224 - fprintf(stderr, "%s.%d: child signaled: %d\n",
51225 + fprintf(stderr, "%s.%d: child signaled: %d\n",
51226 __FILE__, __LINE__,
51229 - fprintf(stderr, "%s.%d: child died somehow: %d\n",
51230 + fprintf(stderr, "%s.%d: child died somehow: %d\n",
51231 __FILE__, __LINE__,
51240 @@ -228,16 +229,16 @@
51241 __FILE__, __LINE__);
51253 void show_version () {
51254 char *b = "spawn-fcgi" "-" PACKAGE_VERSION \
51255 -" - spawns fastcgi processes\n"
51256 +" - spawns fastcgi processes\n"
51258 write(1, b, strlen(b));
51260 @@ -265,7 +266,7 @@
51263 int main(int argc, char **argv) {
51264 - char *fcgi_app = NULL, *changeroot = NULL, *username = NULL,
51265 + char *fcgi_app = NULL, *changeroot = NULL, *username = NULL,
51266 *groupname = NULL, *unixsocket = NULL, *pid_file = NULL,
51268 unsigned short port = 0;
51269 @@ -273,9 +274,9 @@
51275 i_am_root = (getuid() == 0);
51278 while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) {
51280 case 'f': fcgi_app = optarg; break;
51281 @@ -290,137 +291,137 @@
51282 case 'P': pid_file = optarg; /* PID file */ break;
51283 case 'v': show_version(); return 0;
51284 case 'h': show_help(); return 0;
51293 if (fcgi_app == NULL || (port == 0 && unixsocket == NULL)) {
51299 if (unixsocket && port) {
51300 - fprintf(stderr, "%s.%d: %s\n",
51301 + fprintf(stderr, "%s.%d: %s\n",
51302 __FILE__, __LINE__,
51303 "either a unix domain socket or a tcp-port, but not both\n");
51310 if (unixsocket && strlen(unixsocket) > UNIX_PATH_MAX - 1) {
51311 - fprintf(stderr, "%s.%d: %s\n",
51312 + fprintf(stderr, "%s.%d: %s\n",
51313 __FILE__, __LINE__,
51314 "path of the unix socket is too long\n");
51321 if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
51322 /* we are setuid-root */
51324 - fprintf(stderr, "%s.%d: %s\n",
51326 + fprintf(stderr, "%s.%d: %s\n",
51327 __FILE__, __LINE__,
51328 "Are you nuts ? Don't apply a SUID bit to this binary\n");
51337 (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)))) {
51339 if (errno != EEXIST) {
51340 - fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
51341 + fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
51342 __FILE__, __LINE__,
51343 pid_file, strerror(errno));
51350 /* ok, file exists */
51353 if (0 != stat(pid_file, &st)) {
51354 - fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n",
51355 + fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n",
51356 __FILE__, __LINE__,
51357 pid_file, strerror(errno));
51364 /* is it a regular file ? */
51367 if (!S_ISREG(st.st_mode)) {
51368 - fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n",
51369 + fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n",
51370 __FILE__, __LINE__,
51378 if (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
51379 - fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
51380 + fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
51381 __FILE__, __LINE__,
51382 pid_file, strerror(errno));
51391 struct group *grp = NULL;
51392 struct passwd *pwd = NULL;
51395 /* set user and group */
51399 if (NULL == (pwd = getpwnam(username))) {
51400 - fprintf(stderr, "%s.%d: %s, %s\n",
51401 + fprintf(stderr, "%s.%d: %s, %s\n",
51402 __FILE__, __LINE__,
51403 "can't find username", username);
51408 if (pwd->pw_uid == 0) {
51409 - fprintf(stderr, "%s.%d: %s\n",
51410 + fprintf(stderr, "%s.%d: %s\n",
51411 __FILE__, __LINE__,
51412 "I will not set uid to 0\n");
51419 if (NULL == (grp = getgrnam(groupname))) {
51420 - fprintf(stderr, "%s.%d: %s %s\n",
51421 + fprintf(stderr, "%s.%d: %s %s\n",
51422 __FILE__, __LINE__,
51423 - "can't find groupname",
51424 + "can't find groupname",
51428 if (grp->gr_gid == 0) {
51429 - fprintf(stderr, "%s.%d: %s\n",
51430 + fprintf(stderr, "%s.%d: %s\n",
51431 __FILE__, __LINE__,
51432 "I will not set gid to 0\n");
51439 if (-1 == chroot(changeroot)) {
51440 - fprintf(stderr, "%s.%d: %s %s\n",
51441 + fprintf(stderr, "%s.%d: %s %s\n",
51442 __FILE__, __LINE__,
51443 "chroot failed: ", strerror(errno));
51446 if (-1 == chdir("/")) {
51447 - fprintf(stderr, "%s.%d: %s %s\n",
51448 + fprintf(stderr, "%s.%d: %s %s\n",
51449 __FILE__, __LINE__,
51450 "chdir failed: ", strerror(errno));
51456 /* drop root privs */
51458 setgid(grp->gr_gid);
51459 @@ -428,7 +429,7 @@
51461 if (username) setuid(pwd->pw_uid);
51465 return fcgi_spawn_connection(fcgi_app, addr, port, unixsocket, child_count, pid_fd, nofork);
51468 --- ../lighttpd-1.4.11/src/splaytree.c 2005-09-12 21:51:28.000000000 +0300
51469 +++ lighttpd-1.4.12/src/splaytree.c 2006-07-16 00:26:03.000000000 +0300
51470 @@ -56,19 +56,19 @@
51472 #define node_size splaytree_size
51474 -/* Splay using the key i (which may or may not be in the tree.)
51475 - * The starting root is t, and the tree used is defined by rat
51476 +/* Splay using the key i (which may or may not be in the tree.)
51477 + * The starting root is t, and the tree used is defined by rat
51478 * size fields are maintained */
51479 splay_tree * splaytree_splay (splay_tree *t, int i) {
51480 splay_tree N, *l, *r, *y;
51481 int comp, root_size, l_size, r_size;
51484 if (t == NULL) return t;
51485 N.left = N.right = NULL;
51487 root_size = node_size(t);
51488 l_size = r_size = 0;
51492 comp = compare(i, t->key);
51494 @@ -120,7 +120,7 @@
51496 r_size -= 1+node_size(y->right);
51500 l->right = t->left; /* assemble */
51501 r->left = t->right;
51503 --- ../lighttpd-1.4.11/src/splaytree.h 2005-09-12 21:51:13.000000000 +0300
51504 +++ lighttpd-1.4.12/src/splaytree.h 2006-07-16 00:26:03.000000000 +0300
51506 /* This macro returns the size of a node. Unlike "x->size", */
51507 /* it works even if x=NULL. The test could be avoided by using */
51508 /* a special version of NULL which was a real node with size 0. */
51513 --- ../lighttpd-1.4.11/src/stat_cache.c 2005-11-22 15:23:51.000000000 +0200
51514 +++ lighttpd-1.4.12/src/stat_cache.c 2006-07-18 13:03:40.000000000 +0300
51516 #include <stdlib.h>
51517 #include <string.h>
51519 -#include <unistd.h>
51522 #include <assert.h>
51526 #include "sys-mmap.h"
51528 -/* NetBSD 1.3.x needs it */
51529 -#ifndef MAP_FAILED
51530 -# define MAP_FAILED -1
51533 -#ifndef O_LARGEFILE
51534 -# define O_LARGEFILE 0
51537 -#ifndef HAVE_LSTAT
51538 -#define lstat stat
51540 +#include "sys-files.h"
51541 +#include "sys-strings.h"
51544 /* enables debug code for testing if all nodes in the stat-cache as accessable */
51547 * if we get a change-event from FAM, we increment the version in the FAM->dir mapping
51549 - * if the stat()-cache is queried we check if the version id for the directory is the
51550 - * same and return immediatly.
51551 + * if the stat()-cache is queried we check if the version id for the directory is the
51552 + * same and return immediatly.
51556 @@ -62,17 +50,17 @@
51557 * - for each FAMRequest we have to find the version in the directory cache (index as userdata)
51559 * stat <<-> directory <-> FAMRequest
51561 - * if file is deleted, directory is dirty, file is rechecked ...
51563 + * if file is deleted, directory is dirty, file is rechecked ...
51564 * if directory is deleted, directory mapping is removed
51578 @@ -83,16 +71,16 @@
51580 * - the hash-key is used as sorting criteria for a tree
51581 * - a splay-tree is used as we can use the caching effect of it
51585 /* we want to cleanup the stat-cache every few seconds, let's say 10
51587 * - remove entries which are outdated since 30s
51588 * - remove entries which are fresh but havn't been used since 60s
51589 * - if we don't have a stat-cache entry for a directory, release it from the monitor
51593 -#ifdef DEBUG_STAT_CACHE
51594 +#ifdef DEBUG_STAT_CACHE
51598 @@ -105,15 +93,16 @@
51600 stat_cache *stat_cache_init(void) {
51601 stat_cache *fc = NULL;
51604 fc = calloc(1, sizeof(*fc));
51607 fc->dir_name = buffer_init();
51609 fc->fam = calloc(1, sizeof(*fc->fam));
51610 + fc->sock = iosocket_init();
51613 -#ifdef DEBUG_STAT_CACHE
51614 +#ifdef DEBUG_STAT_CACHE
51618 @@ -122,24 +111,24 @@
51620 static stat_cache_entry * stat_cache_entry_init(void) {
51621 stat_cache_entry *sce = NULL;
51624 sce = calloc(1, sizeof(*sce));
51627 sce->name = buffer_init();
51628 sce->etag = buffer_init();
51629 sce->content_type = buffer_init();
51635 static void stat_cache_entry_free(void *data) {
51636 stat_cache_entry *sce = data;
51640 buffer_free(sce->etag);
51641 buffer_free(sce->name);
51642 buffer_free(sce->content_type);
51648 @@ -148,22 +137,22 @@
51649 fam_dir_entry *fam_dir = NULL;
51651 fam_dir = calloc(1, sizeof(*fam_dir));
51654 fam_dir->name = buffer_init();
51660 static void fam_dir_entry_free(void *data) {
51661 fam_dir_entry *fam_dir = data;
51664 if (!fam_dir) return;
51667 FAMCancelMonitor(fam_dir->fc, fam_dir->req);
51670 buffer_free(fam_dir->name);
51671 free(fam_dir->req);
51677 @@ -174,7 +163,7 @@
51678 splay_tree *node = sc->files;
51680 osize = sc->files->size;
51683 stat_cache_entry_free(node->data);
51684 sc->files = splaytree_delete(sc->files, node->key);
51686 @@ -187,12 +176,12 @@
51689 splay_tree *node = sc->dirs;
51692 osize = sc->dirs->size;
51694 fam_dir_entry_free(node->data);
51695 sc->dirs = splaytree_delete(sc->dirs, node->key);
51699 assert(NULL == sc->dirs);
51701 @@ -202,6 +191,7 @@
51705 + iosocket_free(sc->sock);
51709 @@ -212,7 +202,7 @@
51710 static int stat_cache_attr_get(buffer *buf, char *name) {
51716 buffer_prepare_copy(buf, attrlen);
51718 @@ -251,15 +241,15 @@
51721 events = FAMPending(sc->fam);
51724 for (i = 0; i < events; i++) {
51726 fam_dir_entry *fam_dir;
51731 FAMNextEvent(sc->fam, &fe);
51737 @@ -280,7 +270,7 @@
51739 sc->dirs = splaytree_splay(sc->dirs, ndx);
51743 if (node && (node->key == ndx)) {
51744 int osize = splaytree_size(sc->dirs);
51746 @@ -298,17 +288,15 @@
51748 if (revent & FDEVENT_HUP) {
51749 /* fam closed the connection */
51750 - srv->stat_cache->fam_fcce_ndx = -1;
51752 - fdevent_event_del(srv->ev, &(sc->fam_fcce_ndx), FAMCONNECTION_GETFD(sc->fam));
51753 - fdevent_unregister(srv->ev, FAMCONNECTION_GETFD(sc->fam));
51754 + fdevent_event_del(srv->ev, sc->sock);
51755 + fdevent_unregister(srv->ev, sc->sock);
51764 return HANDLER_GO_ON;
51767 @@ -332,7 +320,7 @@
51773 * - HANDLER_FINISHED on cache-miss (don't forget to reopen the file)
51774 * - HANDLER_ERROR on stat() failed -> see errno for problem
51776 @@ -348,16 +336,16 @@
51780 -#ifdef DEBUG_STAT_CACHE
51781 +#ifdef DEBUG_STAT_CACHE
51786 splay_tree *file_node = NULL;
51793 * check if the directory for this file has changed
51796 @@ -366,23 +354,23 @@
51797 file_ndx = hashme(name);
51798 sc->files = splaytree_splay(sc->files, file_ndx);
51800 -#ifdef DEBUG_STAT_CACHE
51801 +#ifdef DEBUG_STAT_CACHE
51802 for (i = 0; i < ctrl.used; i++) {
51803 if (ctrl.ptr[i] == file_ndx) break;
51807 if (sc->files && (sc->files->key == file_ndx)) {
51808 -#ifdef DEBUG_STAT_CACHE
51809 +#ifdef DEBUG_STAT_CACHE
51810 /* it was in the cache */
51811 assert(i < ctrl.used);
51814 - /* we have seen this file already and
51816 + /* we have seen this file already and
51817 * don't stat() it again in the same second */
51819 file_node = sc->files;
51822 sce = file_node->data;
51824 /* check if the name is the same, we might have a collision */
51825 @@ -390,7 +378,7 @@
51826 if (buffer_is_equal(name, sce->name)) {
51827 if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) {
51828 if (sce->stat_ts == srv->cur_ts) {
51831 return HANDLER_GO_ON;
51834 @@ -400,15 +388,15 @@
51835 * file_node is used by the FAM check below to see if we know this file
51836 * and if we can save a stat().
51838 - * BUT, the sce is not reset here as the entry into the cache is ok, we
51839 + * BUT, the sce is not reset here as the entry into the cache is ok, we
51840 * it is just not pointing to our requested file.
51848 -#ifdef DEBUG_STAT_CACHE
51849 +#ifdef DEBUG_STAT_CACHE
51850 if (i != ctrl.used) {
51851 fprintf(stderr, "%s.%d: %08x was already inserted but not found in cache, %s\n", __FILE__, __LINE__, file_ndx, name->ptr);
51853 @@ -424,23 +412,23 @@
51856 dir_ndx = hashme(sc->dir_name);
51859 sc->dirs = splaytree_splay(sc->dirs, dir_ndx);
51862 if (sc->dirs && (sc->dirs->key == dir_ndx)) {
51863 dir_node = sc->dirs;
51867 if (dir_node && file_node) {
51868 /* we found a file */
51871 sce = file_node->data;
51872 fam_dir = dir_node->data;
51875 if (fam_dir->version == sce->dir_version) {
51876 /* the stat()-cache entry is still ok */
51881 return HANDLER_GO_ON;
51884 @@ -448,7 +436,7 @@
51890 * - open() + fstat() on a named-pipe results in a (intended) hang.
51891 * - stat() if regualar file + open() to see if we can read from it is better
51893 @@ -469,16 +457,16 @@
51900 osize = sc->files->size;
51903 sce = stat_cache_entry_init();
51904 buffer_copy_string_buffer(sce->name, name);
51906 - sc->files = splaytree_insert(sc->files, file_ndx, sce);
51907 -#ifdef DEBUG_STAT_CACHE
51909 + sc->files = splaytree_insert(sc->files, file_ndx, sce);
51910 +#ifdef DEBUG_STAT_CACHE
51911 if (ctrl.size == 0) {
51914 @@ -499,29 +487,29 @@
51916 sce->stat_ts = srv->cur_ts;
51918 - /* catch the obvious symlinks
51919 + /* catch the obvious symlinks
51921 * this is not a secure check as we still have a race-condition between
51922 - * the stat() and the open. We can only solve this by
51923 + * the stat() and the open. We can only solve this by
51924 * 1. open() the file
51925 * 2. fstat() the fd
51927 * and keeping the file open for the rest of the time. But this can
51928 * only be done at network level.
51932 if (S_ISLNK(st.st_mode) && !con->conf.follow_symlink) {
51933 return HANDLER_ERROR;
51936 - if (S_ISREG(st.st_mode)) {
51937 + if (S_ISREG(st.st_mode)) {
51938 /* determine mimetype */
51939 buffer_reset(sce->content_type);
51942 for (k = 0; k < con->conf.mimetypes->used; k++) {
51943 data_string *ds = (data_string *)con->conf.mimetypes->data[k];
51944 buffer *type = ds->key;
51947 if (type->used == 0) continue;
51949 /* check if the right side is the same */
51950 @@ -538,8 +526,10 @@
51951 stat_cache_attr_get(sce->content_type, name->ptr);
51954 + } else if (S_ISDIR(st.st_mode)) {
51955 + etag_create(sce->etag, &(sce->st));
51961 (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM)) {
51962 @@ -549,19 +539,19 @@
51963 fam_dir->fc = sc->fam;
51965 buffer_copy_string_buffer(fam_dir->name, sc->dir_name);
51968 fam_dir->version = 1;
51971 fam_dir->req = calloc(1, sizeof(FAMRequest));
51973 - if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr,
51975 + if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr,
51976 fam_dir->req, fam_dir)) {
51978 - log_error_write(srv, __FILE__, __LINE__, "sbs",
51979 - "monitoring dir failed:",
51982 + log_error_write(srv, __FILE__, __LINE__, "sbs",
51983 + "monitoring dir failed:",
51985 FamErrlist[FAMErrno]);
51988 fam_dir_entry_free(fam_dir);
51991 @@ -570,7 +560,7 @@
51992 osize = sc->dirs->size;
51995 - sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir);
51996 + sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir);
51998 assert(sc->dirs->data == fam_dir);
51999 assert(osize == (sc->dirs->size - 1));
52000 @@ -578,9 +568,9 @@
52002 fam_dir = dir_node->data;
52006 /* bind the fam_fc to the stat() cache entry */
52010 sce->dir_version = fam_dir->version;
52011 sce->dir_ndx = dir_ndx;
52012 @@ -594,11 +584,11 @@
52016 - * remove stat() from cache which havn't been stat()ed for
52017 + * remove stat() from cache which havn't been stat()ed for
52018 * more than 10 seconds
52021 - * walk though the stat-cache, collect the ids which are too old
52023 + * walk though the stat-cache, collect the ids which are too old
52024 * and remove them in a second loop
52027 @@ -639,9 +629,9 @@
52028 sc->files = splaytree_splay(sc->files, ndx);
52033 if (node && (node->key == ndx)) {
52034 -#ifdef DEBUG_STAT_CACHE
52035 +#ifdef DEBUG_STAT_CACHE
52037 int osize = splaytree_size(sc->files);
52038 stat_cache_entry *sce = node->data;
52039 @@ -649,7 +639,7 @@
52040 stat_cache_entry_free(node->data);
52041 sc->files = splaytree_delete(sc->files, ndx);
52043 -#ifdef DEBUG_STAT_CACHE
52044 +#ifdef DEBUG_STAT_CACHE
52045 for (j = 0; j < ctrl.used; j++) {
52046 if (ctrl.ptr[j] == ndx) {
52047 ctrl.ptr[j] = ctrl.ptr[--ctrl.used];
52048 --- ../lighttpd-1.4.11/src/stream.c 2005-09-23 21:50:15.000000000 +0300
52049 +++ lighttpd-1.4.12/src/stream.c 2006-07-16 00:26:04.000000000 +0300
52051 #include <sys/types.h>
52052 #include <sys/stat.h>
52054 -#include <unistd.h>
52057 #include "stream.h"
52061 #include "sys-mmap.h"
52062 +#include "sys-files.h"
52065 # define O_BINARY 0
52066 @@ -19,39 +19,39 @@
52070 -#elif defined __WIN32
52071 +#elif defined _WIN32
52079 if (-1 == stat(fn->ptr, &st)) {
52084 f->size = st.st_size;
52087 if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY))) {
52092 f->start = mmap(0, f->size, PROT_READ, MAP_SHARED, fd, 0);
52098 if (MAP_FAILED == f->start) {
52102 -#elif defined __WIN32
52103 - fh = CreateFile(fn->ptr,
52108 - FILE_ATTRIBUTE_READONLY,
52109 +#elif defined _WIN32
52110 + fh = CreateFile(fn->ptr,
52115 + FILE_ATTRIBUTE_READONLY,
52118 if (!fh) return -1;
52123 - FORMAT_MESSAGE_ALLOCATE_BUFFER |
52124 + FORMAT_MESSAGE_ALLOCATE_BUFFER |
52125 FORMAT_MESSAGE_FROM_SYSTEM,
52134 p = MapViewOfFile(mh,
52141 -# error no mmap found
52142 +# error no mmap found
52149 --- ../lighttpd-1.4.11/src/sys-files.h 1970-01-01 03:00:00.000000000 +0300
52150 +++ lighttpd-1.4.12/src/sys-files.h 2006-07-16 00:26:04.000000000 +0300
52152 +#ifndef _SYS_FILES_H_
52153 +#define _SYS_FILES_H_
52155 +#define DIR_SEPERATOR_UNIX '/'
52156 +#define DIR_SEPERATOR_WIN '\\'
52159 +#include <windows.h>
52160 +#include <io.h> /* open */
52161 +#include <direct.h> /* chdir */
52163 +#include "buffer.h"
52165 +#define DIR_SEPERATOR DIR_SEPERATOR_WIN
52167 +#define __S_ISTYPE(mode, mask) (((mode) & _S_IFMT) == (mask))
52169 +#define S_ISDIR(mode) __S_ISTYPE((mode), _S_IFDIR)
52170 +#define S_ISCHR(mode) __S_ISTYPE((mode), _S_IFCHR)
52171 +#define S_ISBLK(mode) __S_ISTYPE((mode), _S_IFBLK)
52172 +#define S_ISREG(mode) __S_ISTYPE((mode), _S_IFREG)
52173 +/* we don't support symlinks */
52174 +#define S_ISLNK(mode) 0
52176 +#define lstat stat
52177 +#define mkstemp mktemp
52178 +#define mkdir(x, y) mkdir(x)
52181 + const char *d_name;
52186 + WIN32_FIND_DATA finddata;
52187 + struct dirent dent;
52190 +DIR *opendir(const char *dn);
52191 +struct dirent *readdir(DIR *d);
52192 +void closedir(DIR *d);
52194 +buffer *filename_unix2local(buffer *b);
52195 +buffer *pathname_unix2local(buffer *b);
52198 +#include <unistd.h>
52199 +#include <dirent.h>
52201 +#define DIR_SEPERATOR DIR_SEPERATOR_UNIX
52203 +#define filename_unix2local(x) (x)
52204 +#define pathname_unix2local(x) (x)
52207 +#define PATHNAME_APPEND_SLASH(x) \
52208 + if (x->used > 1 && x->ptr[x->used - 2] != DIR_SEPERATOR) { \
52209 + char sl[2] = { DIR_SEPERATOR, 0 }; \
52210 + BUFFER_APPEND_STRING_CONST(x, sl); \
52213 +#ifndef O_LARGEFILE
52214 +# define O_LARGEFILE 0
52219 --- ../lighttpd-1.4.11/src/sys-mmap.h 2005-08-11 01:26:34.000000000 +0300
52220 +++ lighttpd-1.4.12/src/sys-mmap.h 2006-07-16 00:26:04.000000000 +0300
52222 #ifndef WIN32_MMAP_H
52223 #define WIN32_MMAP_H
52228 #define MAP_FAILED -1
52229 #define PROT_SHARED 0
52230 --- ../lighttpd-1.4.11/src/sys-process.h 1970-01-01 03:00:00.000000000 +0300
52231 +++ lighttpd-1.4.12/src/sys-process.h 2006-07-16 00:26:04.000000000 +0300
52233 +#ifndef _SYS_PROCESS_H_
52234 +#define _SYS_PROCESS_H_
52237 +#include <process.h>
52239 +/* win32 has no fork() */
52240 +#define kill(x, y)
52241 +#define getpid() 0
52244 +#include <sys/wait.h>
52245 +#include <unistd.h>
52250 --- ../lighttpd-1.4.11/src/sys-socket.h 2005-08-11 01:26:39.000000000 +0300
52251 +++ lighttpd-1.4.12/src/sys-socket.h 2006-07-18 13:03:40.000000000 +0300
52253 #ifndef WIN32_SOCKET_H
52254 #define WIN32_SOCKET_H
52259 #include <winsock2.h>
52261 #define ECONNRESET WSAECONNRESET
52262 #define EINPROGRESS WSAEINPROGRESS
52263 #define EALREADY WSAEALREADY
52264 +#define ENOTCONN WSAENOTCONN
52265 +#define EWOULDBLOCK WSAEWOULDBLOCK
52266 #define ioctl ioctlsocket
52267 #define hstrerror(x) ""
52268 +#define STDIN_FILENO 0
52269 +#define STDOUT_FILENO 1
52270 +#define STDERR_FILENO 2
52271 +#define ssize_t int
52273 +int inet_aton(const char *cp, struct in_addr *inp);
52274 +#define HAVE_INET_ADDR
52275 +#undef HAVE_INET_ATON
52278 #include <sys/socket.h>
52279 #include <sys/ioctl.h>
52281 #include <sys/un.h>
52282 #include <arpa/inet.h>
52285 +#define SUN_LEN(su) \
52286 + (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
52289 +#define closesocket(x) close(x)
52292 +#endif /* !_WIN32 */
52296 + struct sockaddr_in6 ipv6;
52298 + struct sockaddr_in ipv4;
52299 +#ifdef HAVE_SYS_UN_H
52300 + struct sockaddr_un un;
52302 + struct sockaddr plain;
52306 --- ../lighttpd-1.4.11/src/sys-strings.h 1970-01-01 03:00:00.000000000 +0300
52307 +++ lighttpd-1.4.12/src/sys-strings.h 2006-07-16 00:26:03.000000000 +0300
52309 +#ifndef _SYS_STRINGS_H_
52310 +#define _SYS_STRINGS_H_
52313 +#define strcasecmp stricmp
52314 +#define strncasecmp strnicmp
52315 +#define strtoll(p, e, b) _strtoi64(p, e, b)
52320 --- ../lighttpd-1.4.11/tests/LightyTest.pm 2006-01-14 20:32:31.000000000 +0200
52321 +++ lighttpd-1.4.12/tests/LightyTest.pm 2006-07-18 13:03:40.000000000 +0300
52322 @@ -87,14 +87,16 @@
52323 # pre-process configfile if necessary
52326 - unlink($self->{TESTDIR}."/tmp/cfg.file");
52327 - system("cat ".$self->{SRCDIR}."/".$self->{CONFIGFILE}.' | perl -pe "s#\@SRCDIR\@#'.$self->{BASEDIR}.'/tests/#" > '.$self->{TESTDIR}.'/tmp/cfg.file');
52328 + $ENV{'SRCDIR'} = $self->{BASEDIR}.'/tests';
52329 + $ENV{'PORT'} = $self->{PORT};
52331 unlink($self->{LIGHTTPD_PIDFILE});
52333 - system($self->{LIGHTTPD_PATH}." -f ".$self->{TESTDIR}."/tmp/cfg.file -m ".$self->{MODULES_PATH});
52334 + if (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'strace') {
52335 + system("strace -tt -s 512 -o strace ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &");
52336 + } elsif (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'valgrind') {
52337 + 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}." &");
52339 - 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}." &");
52340 + system($self->{LIGHTTPD_PATH}." -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH});
52343 select(undef, undef, undef, 0.1);
52344 @@ -184,7 +186,7 @@
52345 (my $h = $1) =~ tr/[A-Z]/[a-z]/;
52347 if (defined $resp_hdr{$h}) {
52348 - diag(sprintf("header %s is duplicated: %s and %s\n",
52349 + diag(sprintf("header '%s' is duplicated: '%s' and '%s'\n",
52350 $h, $resp_hdr{$h}, $2));
52352 $resp_hdr{$h} = $2;
52353 @@ -196,6 +198,9 @@
52357 + $t->{etag} = $resp_hdr{'etag'};
52358 + $t->{date} = $resp_hdr{'date'};
52361 if (defined $resp_hdr{"content-length"}) {
52362 $resp_body = substr($lines, 0, $resp_hdr{"content-length"});
52363 --- ../lighttpd-1.4.11/tests/Makefile.am 2005-09-16 15:48:40.000000000 +0300
52364 +++ lighttpd-1.4.12/tests/Makefile.am 2006-07-16 00:26:05.000000000 +0300
52365 @@ -39,10 +39,18 @@
52380 + proxy-backend-1.conf \
52381 + proxy-backend-2.conf
52384 TESTS_ENVIRONMENT=$(srcdir)/wrapper.sh $(srcdir) $(top_builddir)
52385 --- ../lighttpd-1.4.11/tests/bug-06.conf 2005-08-27 17:44:19.000000000 +0300
52386 +++ lighttpd-1.4.12/tests/bug-06.conf 2006-07-16 00:26:04.000000000 +0300
52388 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52389 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52390 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52391 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52393 ## bind to port (default: 80)
52397 ## bind to localhost (default: all interfaces)
52398 server.bind = "localhost"
52399 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52400 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52401 server.name = "www.example.org"
52402 server.tag = "Apache 1.3.29"
52405 ######################## MODULE CONFIG ############################
52408 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52409 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52411 mimetype.assign = ( ".png" => "image/png",
52412 ".jpg" => "image/jpeg",
52414 ".c" => "text/plain",
52415 ".conf" => "text/plain" )
52417 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52418 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52419 compress.filetype = ("text/plain", "text/html")
52421 setenv.add-environment = ( "TRAC_ENV" => "foo")
52423 "host" => "127.0.0.1",
52425 # "mode" => "authorizer",
52426 -# "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
52427 +# "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
52431 @@ -106,7 +106,7 @@
52432 ssl.pemfile = "server.pem"
52434 auth.backend = "plain"
52435 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52436 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52437 auth.backend.plain.groupfile = "lighttpd.group"
52439 auth.backend.ldap.hostname = "localhost"
52440 @@ -149,15 +149,15 @@
52441 status.config-url = "/server-config"
52443 simple-vhost.document-root = "pages"
52444 -simple-vhost.server-root = "@SRCDIR@/tmp/lighttpd/servers/"
52445 +simple-vhost.server-root = env.SRCDIR + "/tmp/lighttpd/servers/"
52446 simple-vhost.default-host = "www.example.org"
52448 $HTTP["host"] == "vvv.example.org" {
52449 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52450 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52453 $HTTP["host"] == "zzz.example.org" {
52454 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52455 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52456 server.name = "zzz.example.org"
52459 --- ../lighttpd-1.4.11/tests/bug-12.conf 2005-08-27 17:44:19.000000000 +0300
52460 +++ lighttpd-1.4.12/tests/bug-12.conf 2006-07-16 00:26:04.000000000 +0300
52462 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52463 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52464 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52465 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52467 ## bind to port (default: 80)
52471 ## bind to localhost (default: all interfaces)
52472 server.bind = "localhost"
52473 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52474 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52475 server.name = "www.example.org"
52476 server.tag = "Apache 1.3.29"
52479 ######################## MODULE CONFIG ############################
52482 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52483 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52485 mimetype.assign = ( ".png" => "image/png",
52486 ".jpg" => "image/jpeg",
52488 ".c" => "text/plain",
52489 ".conf" => "text/plain" )
52491 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52492 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52493 compress.filetype = ("text/plain", "text/html")
52495 setenv.add-environment = ( "TRAC_ENV" => "foo")
52497 "host" => "127.0.0.1",
52499 # "mode" => "authorizer",
52500 -# "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
52501 +# "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
52505 @@ -108,7 +108,7 @@
52506 ssl.pemfile = "server.pem"
52508 auth.backend = "plain"
52509 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52510 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52511 auth.backend.plain.groupfile = "lighttpd.group"
52513 auth.backend.ldap.hostname = "localhost"
52514 @@ -151,15 +151,15 @@
52515 status.config-url = "/server-config"
52517 simple-vhost.document-root = "pages"
52518 -simple-vhost.server-root = "@SRCDIR@/tmp/lighttpd/servers/"
52519 +simple-vhost.server-root = env.SRCDIR + "/tmp/lighttpd/servers/"
52520 simple-vhost.default-host = "www.example.org"
52522 $HTTP["host"] == "vvv.example.org" {
52523 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52524 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52527 $HTTP["host"] == "zzz.example.org" {
52528 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52529 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52530 server.name = "zzz.example.org"
52533 --- ../lighttpd-1.4.11/tests/cachable.t 1970-01-01 03:00:00.000000000 +0300
52534 +++ lighttpd-1.4.12/tests/cachable.t 2006-07-18 13:03:40.000000000 +0300
52536 +#!/usr/bin/env perl
52538 + # add current source dir to the include-path
52539 + # we need this for make distcheck
52540 + (my $srcdir = $0) =~ s#/[^/]+$#/#;
52541 + unshift @INC, $srcdir;
52546 +use Test::More tests => 12;
52549 +my $tf = LightyTest->new();
52552 +$tf->{CONFIGFILE} = 'lighttpd.conf';
52554 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
52556 +## check if If-Modified-Since, If-None-Match works
52558 +$t->{REQUEST} = ( <<EOF
52560 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT
52563 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52564 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since');
52566 +$t->{REQUEST} = ( <<EOF
52568 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52571 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Last-Modified' => ''} ];
52572 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since, comment');
52574 +my $now = $t->{date};
52576 +$t->{REQUEST} = ( <<EOF
52578 +If-Modified-Since: $now
52581 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52582 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since');
52584 +$t->{REQUEST} = ( <<EOF
52586 +If-Modified-Since: $now; foo
52589 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52590 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since, comment');
52592 +$t->{REQUEST} = ( <<EOF
52594 +If-None-Match: foo
52597 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+ETag' => ''} ];
52598 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
52600 +my $etag = $t->{etag};
52602 +$t->{REQUEST} = ( <<EOF
52604 +If-None-Match: $etag
52607 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52608 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
52610 +$t->{REQUEST} = ( <<EOF
52612 +If-None-Match: $etag
52613 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52616 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52617 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + old Last-Modified');
52619 +$t->{REQUEST} = ( <<EOF
52621 +If-None-Match: $etag
52622 +If-Modified-Since: $now; foo
52625 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52626 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag, Last-Modified + comment');
52628 +$t->{REQUEST} = ( <<EOF
52630 +If-None-Match: Foo
52631 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52634 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52635 +ok($tf->handle_http($t) == 0, 'Conditional GET - old ETAG + old Last-Modified');
52637 +$t->{REQUEST} = ( <<EOF
52639 +If-None-Match: $etag
52640 +If-Modified-Since: $now foo
52643 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 412 } ];
52644 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + Last-Modified + overlong timestamp');
52646 +ok($tf->stop_proc == 0, "Stopping lighttpd");
52648 --- ../lighttpd-1.4.11/tests/condition.conf 2005-08-27 17:44:19.000000000 +0300
52649 +++ lighttpd-1.4.12/tests/condition.conf 2006-07-16 00:26:05.000000000 +0300
52651 debug.log-request-handling = "enable"
52652 debug.log-condition-handling = "enable"
52654 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52655 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52656 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52657 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52659 ## bind to port (default: 80)
52662 ## bind to localhost (default: all interfaces)
52663 server.bind = "localhost"
52664 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52665 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52666 server.name = "www.example.org"
52667 server.tag = "Apache 1.3.29"
52669 @@ -22,25 +22,25 @@
52670 ######################## MODULE CONFIG ############################
52673 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52674 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52676 mimetype.assign = ( ".html" => "text/html" )
52678 url.redirect = ("^" => "/default")
52680 $HTTP["host"] == "www.example.org" {
52681 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52682 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52683 server.name = "www.example.org"
52684 url.redirect = ("^" => "/match_1")
52686 else $HTTP["host"] == "test1.example.org" {
52687 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52688 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52689 server.name = "test1.example.org"
52690 url.redirect = ("^" => "/match_2")
52693 else $HTTP["host"] == "test2.example.org" {
52694 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52695 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52696 server.name = "test2.example.org"
52697 url.redirect = ("^" => "/match_3")
52702 else $HTTP["host"] == "test3.example.org" {
52703 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52704 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52705 server.name = "test3.example.org"
52706 url.redirect = ("^" => "/match_4")
52708 --- ../lighttpd-1.4.11/tests/core-keepalive.t 2005-11-17 15:54:19.000000000 +0200
52709 +++ lighttpd-1.4.12/tests/core-keepalive.t 2006-07-16 00:26:05.000000000 +0300
52712 GET /12345.txt HTTP/1.0
52713 Host: 123.example.org
52714 -Connection: keep-alive
52718 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } , { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52719 --- ../lighttpd-1.4.11/tests/default.conf 1970-01-01 03:00:00.000000000 +0300
52720 +++ lighttpd-1.4.12/tests/default.conf 2006-07-16 00:26:05.000000000 +0300
52722 +server.name = "www.example.org"
52724 +## bind to port (default: 80)
52725 +server.port = env.PORT
52728 +server.dir-listing = "enable"
52730 +#server.event-handler = "linux-sysepoll"
52731 +#server.event-handler = "linux-rtsig"
52733 +server.modules = (
52740 + "mod_simple_vhost",
52742 + "mod_secdownload",
52749 + "mod_accesslog" )
52751 +server.indexfiles = ( "index.php", "index.html",
52752 + "index.htm", "default.htm" )
52754 +ssi.extension = ( ".shtml" )
52756 +######################## MODULE CONFIG ############################
52759 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52760 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52762 +mimetype.assign = ( ".png" => "image/png",
52763 + ".jpg" => "image/jpeg",
52764 + ".jpeg" => "image/jpeg",
52765 + ".gif" => "image/gif",
52766 + ".html" => "text/html",
52767 + ".htm" => "text/html",
52768 + ".pdf" => "application/pdf",
52769 + ".swf" => "application/x-shockwave-flash",
52770 + ".spl" => "application/futuresplash",
52771 + ".txt" => "text/plain",
52772 + ".tar.gz" => "application/x-tgz",
52773 + ".tgz" => "application/x-tgz",
52774 + ".gz" => "application/x-gzip",
52775 + ".c" => "text/plain",
52776 + ".conf" => "text/plain" )
52778 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52779 +compress.filetype = ("text/plain", "text/html")
52781 +setenv.add-environment = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
52783 +cgi.assign = ( ".pl" => "/usr/bin/perl",
52784 + ".cgi" => "/usr/bin/perl",
52785 + ".py" => "/usr/bin/python" )
52787 +userdir.include-user = ( "jan" )
52788 +userdir.path = "/"
52790 +ssl.engine = "disable"
52791 +ssl.pemfile = "server.pem"
52793 +auth.backend = "plain"
52794 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52795 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
52796 +auth.backend.plain.groupfile = "lighttpd.group"
52798 +auth.backend.ldap.hostname = "localhost"
52799 +auth.backend.ldap.base-dn = "dc=my-domain,dc=com"
52800 +auth.backend.ldap.filter = "(uid=$)"
52802 +auth.require = ( "/server-status" =>
52804 + "method" => "digest",
52805 + "realm" => "download archiv",
52806 + "require" => "valid-user"
52810 + "method" => "basic",
52811 + "realm" => "download archiv",
52812 + "require" => "user=jan"
52814 + "/server-config" =>
52816 + "method" => "basic",
52817 + "realm" => "download archiv",
52818 + "require" => "valid-user"
52822 +url.access-deny = ( "~", ".inc")
52824 +url.redirect = ( "^/redirect/$" => "http://localhost:2048/" )
52826 +url.rewrite = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
52827 + "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
52829 +#### status module
52830 +status.status-url = "/server-status"
52831 +status.config-url = "/server-config"
52833 --- ../lighttpd-1.4.11/tests/docroot/www/dummydir/.svn/entries 2006-03-09 19:21:49.000000000 +0200
52834 +++ lighttpd-1.4.12/tests/docroot/www/dummydir/.svn/entries 2006-07-18 17:34:32.000000000 +0300
52838 uuid="152afb58-edef-0310-8abb-c4023f1b3aa9"
52839 - revision="1040"/>
52840 + repos="svn://svn.lighttpd.net/lighttpd"
52841 + revision="1202"/>
52843 --- ../lighttpd-1.4.11/tests/fastcgi-10.conf 2005-08-31 23:36:34.000000000 +0300
52844 +++ lighttpd-1.4.12/tests/fastcgi-10.conf 2006-07-16 00:26:04.000000000 +0300
52846 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52847 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52848 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52849 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52851 ## bind to port (default: 80)
52854 ## bind to localhost (default: all interfaces)
52855 server.bind = "localhost"
52856 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52857 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52858 server.name = "www.example.org"
52859 server.tag = "Apache 1.3.29"
52862 ######################## MODULE CONFIG ############################
52865 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52866 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52868 mimetype.assign = ( ".png" => "image/png",
52869 ".jpg" => "image/jpeg",
52871 ".c" => "text/plain",
52872 ".conf" => "text/plain" )
52874 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52875 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52876 compress.filetype = ("text/plain", "text/html")
52880 ssl.pemfile = "server.pem"
52882 auth.backend = "plain"
52883 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52884 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52885 auth.backend.plain.groupfile = "lighttpd.group"
52887 auth.backend.ldap.hostname = "localhost"
52888 @@ -128,11 +128,11 @@
52889 status.config-url = "/server-config"
52891 $HTTP["host"] == "vvv.example.org" {
52892 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52893 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52896 $HTTP["host"] == "zzz.example.org" {
52897 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52898 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52899 server.name = "zzz.example.org"
52902 --- ../lighttpd-1.4.11/tests/fastcgi-13.conf 2006-01-03 12:38:17.000000000 +0200
52903 +++ lighttpd-1.4.12/tests/fastcgi-13.conf 2006-07-18 13:03:40.000000000 +0300
52905 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52906 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52907 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52908 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52910 debug.log-request-header = "enable"
52911 debug.log-response-header = "enable"
52914 ## bind to localhost (default: all interfaces)
52915 server.bind = "localhost"
52916 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52917 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52918 server.name = "www.example.org"
52919 server.tag = "Apache 1.3.29"
52922 ######################## MODULE CONFIG ############################
52925 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52926 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52928 mimetype.assign = ( ".png" => "image/png",
52929 ".jpg" => "image/jpeg",
52931 ".c" => "text/plain",
52932 ".conf" => "text/plain" )
52934 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52935 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52936 compress.filetype = ("text/plain", "text/html")
52941 "host" => "127.0.0.1",
52943 - "bin-path" => "/home/jan/Documents/php-5.1.0/sapi/cgi/php -c /usr/local/lib/php.ini",
52944 + "bin-path" => "/home/jan/Documents/php-5.1.4/sapi/cgi/php -c /usr/local/lib/php.ini",
52945 "bin-copy-environment" => ( "PATH", "SHELL", "USER" ),
52948 @@ -102,7 +102,7 @@
52949 ssl.pemfile = "server.pem"
52951 auth.backend = "plain"
52952 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52953 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52954 auth.backend.plain.groupfile = "lighttpd.group"
52956 auth.backend.ldap.hostname = "localhost"
52957 @@ -145,11 +145,11 @@
52958 status.config-url = "/server-config"
52960 $HTTP["host"] == "vvv.example.org" {
52961 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52962 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52965 $HTTP["host"] == "zzz.example.org" {
52966 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52967 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52968 server.name = "zzz.example.org"
52971 --- ../lighttpd-1.4.11/tests/fastcgi-auth.conf 2005-08-27 17:44:19.000000000 +0300
52972 +++ lighttpd-1.4.12/tests/fastcgi-auth.conf 2006-07-16 00:26:05.000000000 +0300
52974 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52975 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52976 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52977 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52979 debug.log-request-header = "enable"
52980 debug.log-response-header = "enable"
52983 ## bind to localhost (default: all interfaces)
52984 server.bind = "localhost"
52985 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52986 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52987 server.name = "www.example.org"
52988 server.tag = "Apache 1.3.29"
52991 ######################## MODULE CONFIG ############################
52994 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52995 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52997 mimetype.assign = ( ".png" => "image/png",
52998 ".jpg" => "image/jpeg",
53000 ".c" => "text/plain",
53001 ".conf" => "text/plain" )
53003 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53004 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53005 compress.filetype = ("text/plain", "text/html")
53010 "host" => "127.0.0.1",
53012 - "bin-path" => "@SRCDIR@/fcgi-auth",
53013 + "bin-path" => env.SRCDIR + "/fcgi-auth",
53014 "mode" => "authorizer",
53015 - "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
53016 + "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
53020 @@ -106,7 +106,7 @@
53021 ssl.pemfile = "server.pem"
53023 auth.backend = "plain"
53024 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53025 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53026 auth.backend.plain.groupfile = "lighttpd.group"
53028 auth.backend.ldap.hostname = "localhost"
53029 @@ -149,11 +149,11 @@
53030 status.config-url = "/server-config"
53032 $HTTP["host"] == "vvv.example.org" {
53033 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53034 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53037 $HTTP["host"] == "zzz.example.org" {
53038 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53039 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53040 server.name = "zzz.example.org"
53043 --- ../lighttpd-1.4.11/tests/fastcgi-responder.conf 2005-08-27 17:44:19.000000000 +0300
53044 +++ lighttpd-1.4.12/tests/fastcgi-responder.conf 2006-07-16 00:26:05.000000000 +0300
53046 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53047 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53048 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53049 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53051 #debug.log-request-header = "enable"
53052 #debug.log-response-header = "enable"
53055 ## bind to localhost (default: all interfaces)
53056 server.bind = "localhost"
53057 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53058 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53059 server.name = "www.example.org"
53060 server.tag = "Apache 1.3.29"
53063 ######################## MODULE CONFIG ############################
53066 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53067 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53069 mimetype.assign = ( ".png" => "image/png",
53070 ".jpg" => "image/jpeg",
53072 ".c" => "text/plain",
53073 ".conf" => "text/plain" )
53075 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53076 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53077 compress.filetype = ("text/plain", "text/html")
53080 @@ -90,10 +90,11 @@
53082 "host" => "127.0.0.1",
53084 - "bin-path" => "@SRCDIR@/fcgi-responder",
53085 + "bin-path" => env.SRCDIR + "/fcgi-responder",
53086 "check-local" => "disable",
53089 + "min-procs" => 1,
53090 + "allow-x-send-file" => "enable",
53094 @@ -109,7 +110,7 @@
53095 ssl.pemfile = "server.pem"
53097 auth.backend = "plain"
53098 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53099 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53100 auth.backend.plain.groupfile = "lighttpd.group"
53102 auth.backend.ldap.hostname = "localhost"
53103 @@ -152,11 +153,11 @@
53104 status.config-url = "/server-config"
53106 $HTTP["host"] == "vvv.example.org" {
53107 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53108 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53111 $HTTP["host"] == "zzz.example.org" {
53112 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53113 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53114 server.name = "zzz.example.org"
53117 --- ../lighttpd-1.4.11/tests/fcgi-responder.c 2005-08-11 01:26:55.000000000 +0300
53118 +++ lighttpd-1.4.12/tests/fcgi-responder.c 2006-07-16 00:26:05.000000000 +0300
53121 int num_requests = 2;
53123 - while (num_requests > 0 &&
53124 - FCGI_Accept() >= 0) {
53127 - if (NULL != (p = getenv("QUERY_STRING"))) {
53128 + while (num_requests > 0 && FCGI_Accept() >= 0) {
53130 + char* doc_root = NULL;
53131 + char fname[4096];
53132 + char* pfname = (char *)fname;
53134 + doc_root = getenv("DOCUMENT_ROOT");
53135 + p = getenv("QUERY_STRING");
53137 + if (NULL != p && NULL != doc_root) {
53138 + snprintf(pfname, sizeof(fname), "%s/phpinfo.php", doc_root);
53139 if (0 == strcmp(p, "lf")) {
53140 printf("Status: 200 OK\n\n");
53141 } else if (0 == strcmp(p, "crlf")) {
53143 printf("Status: 200 OK\r\n");
53146 + } else if (0 == strcmp(p,"x-lighttpd-send-file")) {
53147 + printf("Status: 200 OK\r\n");
53148 + printf("X-LIGHTTPD-send-file: %s\r\n", pfname);
53150 + } else if (0 == strcmp(p,"xsendfile")) {
53151 + printf("Status: 200 OK\r\n");
53152 + printf("X-Sendfile: %s\r\n", pfname);
53154 + } else if (0 == strcmp(p,"xsendfile-mixed-case")) {
53155 + printf("Status: 200 OK\r\n");
53156 + printf("X-SeNdFiLe: %s\r\n", pfname);
53158 } else if (0 == strcmp(p, "die-at-end")) {
53159 printf("Status: 200 OK\r\n\r\n");
53161 --- ../lighttpd-1.4.11/tests/lighttpd.conf 2006-03-09 15:26:58.000000000 +0200
53162 +++ lighttpd-1.4.12/tests/lighttpd.conf 2006-07-16 00:26:05.000000000 +0300
53164 -debug.log-request-handling = "enable"
53165 -debug.log-condition-handling = "enable"
53166 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53167 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53168 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53169 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53170 +server.tag = "Apache 1.3.29"
53172 ## 64 Mbyte ... nice limit
53173 server.max-request-size = 65000
53175 -## bind to port (default: 80)
53176 -server.port = 2048
53177 +include "default.conf"
53179 -## bind to localhost (default: all interfaces)
53180 -server.bind = "localhost"
53181 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53182 -server.name = "www.example.org"
53183 -server.tag = "Apache 1.3.29"
53185 -server.dir-listing = "enable"
53187 -#server.event-handler = "linux-sysepoll"
53188 -#server.event-handler = "linux-rtsig"
53190 -#server.modules.path = ""
53191 -server.modules = (
53194 - "mod_secdownload",
53200 - "mod_simple_vhost",
53203 -# "mod_localizer",
53209 - "mod_accesslog" )
53211 -server.indexfiles = ( "index.php", "index.html",
53212 - "index.htm", "default.htm" )
53215 -######################## MODULE CONFIG ############################
53217 -ssi.extension = ( ".shtml" )
53219 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53221 -mimetype.assign = ( ".png" => "image/png",
53222 - ".jpg" => "image/jpeg",
53223 - ".jpeg" => "image/jpeg",
53224 - ".gif" => "image/gif",
53225 - ".html" => "text/html",
53226 - ".htm" => "text/html",
53227 - ".pdf" => "application/pdf",
53228 - ".swf" => "application/x-shockwave-flash",
53229 - ".spl" => "application/futuresplash",
53230 - ".txt" => "text/plain",
53231 - ".tar.gz" => "application/x-tgz",
53232 - ".tgz" => "application/x-tgz",
53233 - ".gz" => "application/x-gzip",
53234 - ".c" => "text/plain",
53235 - ".conf" => "text/plain" )
53236 +setenv.add-request-header = ( "FOO" => "foo")
53237 +setenv.add-response-header = ( "BAR" => "foo")
53239 $HTTP["host"] == "cache.example.org" {
53240 - compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53241 + compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53243 -compress.filetype = ("text/plain", "text/html")
53245 -setenv.add-environment = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
53246 -setenv.add-request-header = ( "FOO" => "foo")
53247 -setenv.add-response-header = ( "BAR" => "foo")
53249 $HTTP["url"] =~ "\.pdf$" {
53250 server.range-requests = "disable"
53251 @@ -85,76 +23,31 @@
53252 "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
53256 -cgi.assign = ( ".pl" => "/usr/bin/perl",
53257 - ".cgi" => "/usr/bin/perl",
53258 - ".py" => "/usr/bin/python" )
53260 -userdir.include-user = ( "jan" )
53261 -userdir.path = "/"
53263 -ssl.engine = "disable"
53264 -ssl.pemfile = "server.pem"
53266 $HTTP["host"] == "auth-htpasswd.example.org" {
53267 auth.backend = "htpasswd"
53270 -auth.backend = "plain"
53271 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53273 -auth.backend.htpasswd.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.htpasswd"
53276 -auth.require = ( "/server-status" =>
53278 - "method" => "digest",
53279 - "realm" => "download archiv",
53280 - "require" => "group=www|user=jan|host=192.168.2.10"
53282 - "/server-config" =>
53284 - "method" => "basic",
53285 - "realm" => "download archiv",
53286 - "require" => "valid-user"
53290 -url.access-deny = ( "~", ".inc")
53292 -url.rewrite = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
53293 - "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
53295 -expire.url = ( "/expire/access" => "access 2 hours",
53296 - "/expire/modification" => "access plus 1 seconds 2 minutes")
53298 -#cache.cache-dir = "/home/weigon/wwwroot/cache/"
53300 -#### status module
53301 -status.status-url = "/server-status"
53302 -status.config-url = "/server-config"
53304 $HTTP["host"] == "vvv.example.org" {
53305 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53306 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53307 secdownload.secret = "verysecret"
53308 - secdownload.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53309 + secdownload.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53310 secdownload.uri-prefix = "/sec/"
53311 secdownload.timeout = 120
53314 $HTTP["host"] == "zzz.example.org" {
53315 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53316 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53317 server.name = "zzz.example.org"
53320 $HTTP["host"] == "no-simple.example.org" {
53321 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/123.example.org/pages/"
53322 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/123.example.org/pages/"
53323 server.name = "zzz.example.org"
53326 $HTTP["host"] !~ "(no-simple\.example\.org)" {
53327 simple-vhost.document-root = "pages"
53328 - simple-vhost.server-root = "@SRCDIR@/tmp/lighttpd/servers/"
53329 + simple-vhost.server-root = env.SRCDIR + "/tmp/lighttpd/servers/"
53330 simple-vhost.default-host = "www.example.org"
53333 --- ../lighttpd-1.4.11/tests/lowercase.conf 1970-01-01 03:00:00.000000000 +0300
53334 +++ lighttpd-1.4.12/tests/lowercase.conf 2006-07-16 00:26:05.000000000 +0300
53336 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53337 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53339 +## bind to port (default: 80)
53340 +server.port = 2048
53342 +## bind to localhost (default: all interfaces)
53343 +server.bind = "localhost"
53344 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53346 +server.force-lowercase-filenames = "enable"
53348 +server.dir-listing = "enable"
53350 +server.modules = (
53353 + "mod_secdownload",
53362 +server.indexfiles = ( "index.php", "index.html",
53363 + "index.htm", "default.htm" )
53366 +######################## MODULE CONFIG ############################
53368 +mimetype.assign = ( ".png" => "image/png",
53369 + ".jpg" => "image/jpeg",
53370 + ".jpeg" => "image/jpeg",
53371 + ".gif" => "image/gif",
53372 + ".html" => "text/html",
53373 + ".htm" => "text/html",
53374 + ".pdf" => "application/pdf",
53375 + ".swf" => "application/x-shockwave-flash",
53376 + ".spl" => "application/futuresplash",
53377 + ".txt" => "text/plain",
53378 + ".tar.gz" => "application/x-tgz",
53379 + ".tgz" => "application/x-tgz",
53380 + ".gz" => "application/x-gzip",
53381 + ".c" => "text/plain",
53382 + ".conf" => "text/plain" )
53385 +fastcgi.server = ( ".php" => ( ( "host" => "127.0.0.1", "port" => 1026, "broken-scriptfilename" => "enable" ) ),
53386 + "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
53390 +cgi.assign = ( ".pl" => "/usr/bin/perl",
53391 + ".cgi" => "/usr/bin/perl",
53392 + ".py" => "/usr/bin/python" )
53394 +auth.backend = "plain"
53395 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53397 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
53399 +$HTTP["host"] == "lowercase-auth" {
53400 + auth.require = ( "/image.jpg" =>
53402 + "method" => "digest",
53403 + "realm" => "download archiv",
53404 + "require" => "valid-user"
53409 +$HTTP["host"] == "lowercase-deny" {
53410 + url.access-deny = ( ".jpg")
53413 +$HTTP["host"] == "lowercase-exclude" {
53414 + static-file.exclude-extensions = ( ".jpg" )
53416 --- ../lighttpd-1.4.11/tests/lowercase.t 1970-01-01 03:00:00.000000000 +0300
53417 +++ lighttpd-1.4.12/tests/lowercase.t 2006-07-16 00:26:05.000000000 +0300
53419 +#!/usr/bin/env perl
53421 + # add current source dir to the include-path
53422 + # we need this for make distcheck
53423 + (my $srcdir = $0) =~ s#/[^/]+$#/#;
53424 + unshift @INC, $srcdir;
53429 +use Test::More tests => 10;
53432 +my $tf = LightyTest->new();
53435 +$tf->{CONFIGFILE} = 'lowercase.conf';
53437 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
53439 +## check if lower-casing works
53441 +$t->{REQUEST} = ( <<EOF
53442 +GET /image.JPG HTTP/1.0
53445 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53446 +ok($tf->handle_http($t) == 0, 'uppercase access');
53448 +$t->{REQUEST} = ( <<EOF
53449 +GET /image.jpg HTTP/1.0
53452 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53453 +ok($tf->handle_http($t) == 0, 'lowercase access');
53455 +## check that mod-auth works
53457 +$t->{REQUEST} = ( <<EOF
53458 +GET /image.JPG HTTP/1.0
53459 +Host: lowercase-auth
53462 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
53463 +ok($tf->handle_http($t) == 0, 'uppercase access');
53465 +$t->{REQUEST} = ( <<EOF
53466 +GET /image.jpg HTTP/1.0
53467 +Host: lowercase-auth
53470 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
53471 +ok($tf->handle_http($t) == 0, 'lowercase access');
53474 +## check that mod-staticfile exclude works
53475 +$t->{REQUEST} = ( <<EOF
53476 +GET /image.JPG HTTP/1.0
53477 +Host: lowercase-exclude
53480 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53481 +ok($tf->handle_http($t) == 0, 'upper case access to staticfile.exclude-extension');
53483 +$t->{REQUEST} = ( <<EOF
53484 +GET /image.jpg HTTP/1.0
53485 +Host: lowercase-exclude
53488 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53489 +ok($tf->handle_http($t) == 0, 'lowercase access');
53492 +## check that mod-access exclude works
53493 +$t->{REQUEST} = ( <<EOF
53494 +GET /image.JPG HTTP/1.0
53495 +Host: lowercase-deny
53498 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53499 +ok($tf->handle_http($t) == 0, 'uppercase access to url.access-deny protected location');
53501 +$t->{REQUEST} = ( <<EOF
53502 +GET /image.jpg HTTP/1.0
53503 +Host: lowercase-deny
53506 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53507 +ok($tf->handle_http($t) == 0, 'lowercase access');
53511 +ok($tf->stop_proc == 0, "Stopping lighttpd");
53513 --- ../lighttpd-1.4.11/tests/mod-cgi.t 2005-09-01 14:43:05.000000000 +0300
53514 +++ lighttpd-1.4.12/tests/mod-cgi.t 2006-07-18 13:03:40.000000000 +0300
53516 GET /nph-status.pl HTTP/1.0
53519 -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53520 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 502 } ];
53521 ok($tf->handle_http($t) == 0, 'NPH + perl, Bug #14');
53523 $t->{REQUEST} = ( <<EOF
53524 --- ../lighttpd-1.4.11/tests/mod-fastcgi.t 2006-03-09 15:30:45.000000000 +0200
53525 +++ lighttpd-1.4.12/tests/mod-fastcgi.t 2006-07-18 13:03:40.000000000 +0300
53530 -use Test::More tests => 47;
53531 +use Test::More tests => 49;
53534 my $tf = LightyTest->new();
53539 - skip "no PHP running on port 1026", 30 unless $tf->listening_on(1026);
53540 + skip "no PHP running on port 1026", 29 unless $tf->listening_on(1026);
53542 ok($tf->start_proc == 0, "Starting lighttpd") or die();
53544 @@ -223,7 +223,7 @@
53548 - skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.0/sapi/cgi/php";
53549 + skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.4/sapi/cgi/php";
53550 $tf->{CONFIGFILE} = 'fastcgi-13.conf';
53551 ok($tf->start_proc == 0, "Starting lighttpd with $tf->{CONFIGFILE}") or die();
53552 $t->{REQUEST} = ( <<EOF
53553 @@ -285,6 +285,34 @@
53554 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'test123' } ];
53555 ok($tf->handle_http($t) == 0, 'line-ending \r\n + \r\n');
53557 + # X-LIGHTTPD-send-file
53558 + $t->{REQUEST} = ( <<EOF
53559 +GET /index.fcgi?x-lighttpd-send-file HTTP/1.0
53560 +Host: www.example.org
53563 + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53565 + ok($tf->handle_http($t) == 0, 'X-LIGHTTPD-send-file');
53567 + $t->{REQUEST} = ( <<EOF
53568 +GET /index.fcgi?xsendfile HTTP/1.0
53569 +Host: www.example.org
53572 + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53574 + ok($tf->handle_http($t) == 0, 'X-Sendfile');
53576 + $t->{REQUEST} = ( <<EOF
53577 +GET /index.fcgi?xsendfile-mixed-case HTTP/1.0
53578 +Host: www.example.org
53581 + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53583 + ok($tf->handle_http($t) == 0, 'X-SeNdFiLe in mixed case');
53585 $t->{REQUEST} = ( <<EOF
53586 GET /index.fcgi?die-at-end HTTP/1.0
53587 Host: www.example.org
53588 --- ../lighttpd-1.4.11/tests/mod-proxy.t 1970-01-01 03:00:00.000000000 +0300
53589 +++ lighttpd-1.4.12/tests/mod-proxy.t 2006-07-18 13:03:40.000000000 +0300
53591 +#!/usr/bin/env perl
53593 + # add current source dir to the include-path
53594 + # we need this for make distcheck
53595 + (my $srcdir = $0) =~ s#/[^/]+$#/#;
53596 + unshift @INC, $srcdir;
53601 +use Test::More tests => 21;
53604 +my $tf_proxy = LightyTest->new();
53605 +my $tf_backend1 = LightyTest->new();
53606 +my $tf_backend2 = LightyTest->new();
53610 +## we need two procs
53611 +## 1. the real webserver
53612 +## 2. the proxy server
53615 + skip "disabled for now", 21;
53616 +$tf_proxy->{PORT} = 2048;
53617 +$tf_proxy->{CONFIGFILE} = 'proxy.conf';
53618 +$tf_proxy->{LIGHTTPD_PIDFILE} = $tf_proxy->{SRCDIR}.'/tmp/lighttpd/lighttpd-proxy.pid';
53620 +$tf_backend1->{PORT} = 2050;
53621 +$tf_backend1->{CONFIGFILE} = 'proxy-backend-1.conf';
53622 +$tf_backend1->{LIGHTTPD_PIDFILE} = $tf_backend1->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-1.pid';
53624 +$tf_backend2->{PORT} = 2051;
53625 +$tf_backend2->{CONFIGFILE} = 'proxy-backend-2.conf';
53626 +$tf_backend2->{LIGHTTPD_PIDFILE} = $tf_backend2->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-2.pid';
53629 +ok($tf_backend1->start_proc == 0, "Starting lighttpd") or die();
53631 +ok($tf_proxy->start_proc == 0, "Starting lighttpd as proxy") or die();
53635 +$t->{REQUEST} = ( <<EOF
53636 +GET /index.html HTTP/1.0
53637 +Host: www.example.org
53640 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53641 +ok($tf_proxy->handle_http($t) == 0, 'valid request');
53643 +$t->{REQUEST} = ( <<EOF
53644 +GET /index.html HTTP/1.0
53645 +Host: www.example.org
53648 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Server' => 'proxy-backend-1' } ];
53649 +ok($tf_proxy->handle_http($t) == 0, 'drop Server from real server');
53651 +$t->{REQUEST} = ( <<EOF
53652 +GET /balance-rr/foo HTTP/1.0
53653 +Host: www.example.org
53656 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53657 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one backend');
53659 +$t->{REQUEST} = ( <<EOF
53660 +GET /balance-rr/foo HTTP/1.0
53661 +Host: www.example.org
53664 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53665 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one host down, failover');
53667 +$t->{REQUEST} = ( <<EOF
53668 +GET /balance-fair/foo HTTP/1.0
53669 +Host: www.example.org
53672 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53673 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - one backend');
53675 +## backend 2 starting
53676 +ok($tf_backend2->start_proc == 0, "Starting second proxy backend") or die();
53678 +$t->{REQUEST} = ( <<EOF
53679 +GET /balance-rr/foo HTTP/1.0
53680 +Host: www.example.org
53683 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53684 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 1');
53686 +$t->{REQUEST} = ( <<EOF
53687 +GET /balance-rr/foo HTTP/1.0
53688 +Host: www.example.org
53691 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53692 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 2');
53694 +$t->{REQUEST} = ( <<EOF
53695 +GET /balance-hash/foo HTTP/1.0
53696 +Host: www.example.org
53699 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53700 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1');
53702 +$t->{REQUEST} = ( <<EOF
53703 +GET /balance-hash/foo HTTP/1.0
53704 +Host: www.example.org
53707 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53708 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1 - same URL');
53710 +$t->{REQUEST} = ( <<EOF
53711 +GET /balance-hash/bar HTTP/1.0
53712 +Host: www.example.org
53715 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53716 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2');
53718 +$t->{REQUEST} = ( <<EOF
53719 +GET /balance-hash/bar HTTP/1.0
53720 +Host: www.example.org
53723 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53724 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2 - same URL');
53726 +## backend 1 stopping, failover
53727 +ok($tf_backend1->stop_proc == 0, "Stopping backend 1");
53729 +$t->{REQUEST} = ( <<EOF
53730 +GET /balance-hash/foo HTTP/1.0
53731 +Host: www.example.org
53734 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53735 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2');
53737 +$t->{REQUEST} = ( <<EOF
53738 +GET /balance-hash/bar HTTP/1.0
53739 +Host: www.example.org
53742 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53743 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2 - same URL');
53745 +$t->{REQUEST} = ( <<EOF
53746 +GET /balance-rr/foo HTTP/1.0
53747 +Host: www.example.org
53750 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53751 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - failover to backend 2');
53753 +$t->{REQUEST} = ( <<EOF
53754 +GET /balance-fair/foo HTTP/1.0
53755 +Host: www.example.org
53758 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53759 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - failover to backend 2');
53762 +ok($tf_backend2->stop_proc == 0, "Stopping lighttpd");
53764 +ok($tf_proxy->stop_proc == 0, "Stopping lighttpd proxy");
53766 --- ../lighttpd-1.4.11/tests/proxy-backend-1.conf 1970-01-01 03:00:00.000000000 +0300
53767 +++ lighttpd-1.4.12/tests/proxy-backend-1.conf 2006-07-16 00:26:05.000000000 +0300
53769 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53770 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-1.pid"
53772 +include "default.conf"
53775 +server.tag = "proxy-backend-1"
53776 --- ../lighttpd-1.4.11/tests/proxy-backend-2.conf 1970-01-01 03:00:00.000000000 +0300
53777 +++ lighttpd-1.4.12/tests/proxy-backend-2.conf 2006-07-16 00:26:04.000000000 +0300
53779 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53780 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-2.pid"
53782 +include "default.conf"
53785 +server.tag = "proxy-backend-2"
53786 --- ../lighttpd-1.4.11/tests/proxy.conf 1970-01-01 03:00:00.000000000 +0300
53787 +++ lighttpd-1.4.12/tests/proxy.conf 2006-07-16 00:26:05.000000000 +0300
53789 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53790 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd-proxy.pid"
53791 +server.tag = "proxy"
53793 +include "default.conf"
53795 +## 127.0.0.1 and 127.0.0.2 are the same host
53797 + "" => (( "host" => "127.0.0.1",
53798 + "port" => 2050 ),
53799 + ( "host" => "127.0.0.2",
53803 +$HTTP["url"] =~ "^/balance-rr/" {
53804 + proxy.balance = "round-robin"
53807 +$HTTP["url"] =~ "^/balance-hash/" {
53808 + proxy.balance = "hash"
53811 +$HTTP["url"] =~ "^/balance-fair/" {
53812 + proxy.balance = "fair"
53815 --- ../lighttpd-1.4.11/tests/var-include.conf 2005-08-27 17:44:19.000000000 +0300
53816 +++ lighttpd-1.4.12/tests/var-include.conf 2006-07-16 00:26:05.000000000 +0300
53818 debug.log-request-handling = "enable"
53819 debug.log-condition-handling = "enable"
53821 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53822 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53823 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53824 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53826 ## bind to port (default: 80)
53829 ## bind to localhost (default: all interfaces)
53830 server.bind = "localhost"
53831 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53832 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53833 server.name = "www.example.org"
53834 server.tag = "Apache 1.3.29"
53836 @@ -21,19 +21,19 @@
53837 ######################## MODULE CONFIG ############################
53840 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53841 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53843 mimetype.assign = ( ".html" => "text/html" )
53845 url.redirect = ("^" => "/default")
53847 $HTTP["host"] == "www.example.org" {
53848 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53849 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53850 server.name = "www.example.org"
53851 url.redirect = ("^" => "/redirect")
53853 $HTTP["host"] == "test.example.org" {
53854 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53855 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53856 server.name = "test.example.org"