1 --- ../lighttpd-1.4.11/NEWS 2006-03-09 19:34:33.000000000 +0200
2 +++ lighttpd-1.5.0/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.5.0/configure.in 2006-09-07 00:57: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.5.0, jan@kneschke.de)
35 AC_CONFIG_SRCDIR([src/server.c])
42 -AC_CHECK_MEMBER(struct tm.tm_gmtoff,AC_DEFINE([HAVE_STRUCT_TM_GMTOFF],[1],[gmtoff in struct tm]),,[#include <time.h>])
43 +AC_CHECK_MEMBER(struct tm.tm_gmtoff,[AC_DEFINE([HAVE_STRUCT_TM_GMTOFF],[1],[gmtoff in struct tm])],,[#include <time.h>])
44 AC_CHECK_TYPES(struct sockaddr_storage,,,[#include <sys/socket.h>])
45 AC_CHECK_TYPES(socklen_t,,,[#include <sys/types.h>
46 #include <sys/socket.h>])
48 AC_DEFINE([HAVE_SQLITE3], [1], [libsqlite3])
49 AC_DEFINE([HAVE_SQLITE3_H], [1], [sqlite3.h])
52 + AC_MSG_CHECKING(for locks in mod_webdav)
53 + AC_ARG_WITH(webdav-locks, AC_HELP_STRING([--with-webdav-locks],[locks in mod_webdav]),
54 + [WITH_WEBDAV_LOCKS=$withval],[WITH_WEBDAV_LOCKS=no])
55 + AC_MSG_RESULT([$WITH_WEBDAV_LOCKS])
57 + if test "$WITH_WEBDAV_LOCKS" != "no"; then
58 + AC_CHECK_LIB(uuid, uuid_unparse, [
59 + AC_CHECK_HEADERS([uuid/uuid.h],[
61 + AC_DEFINE([HAVE_UUID], [1], [libuuid])
62 + AC_DEFINE([HAVE_UUID_H], [1], [uuid/uuid.h is available])
72 AC_MSG_RESULT($WITH_LUA)
73 if test "$WITH_LUA" != "no"; then
74 - AC_PATH_PROG(LUACONFIG, lua-config)
76 - if test x"$LUACONFIG" != x; then
77 - LUA_CFLAGS=`$LUACONFIG --include`
78 - LUA_LIBS=`$LUACONFIG --libs --extralibs`
80 + PKG_CHECK_MODULES(LUA, lua >= 5.1, [
81 AC_DEFINE([HAVE_LUA], [1], [liblua])
82 AC_DEFINE([HAVE_LUA_H], [1], [lua.h])
84 - AC_CHECK_LIB(lua, lua_open, [
85 - AC_CHECK_HEADERS([lua.h],[
86 - LUA_LIBS="-llua -llualib"
87 - AC_DEFINE([HAVE_LUA], [1], [liblua])
88 - AC_DEFINE([HAVE_LUA_H], [1], [lua.h])
93 - if test x"$LUA_LIBS" = x; then
95 - PKG_CHECK_MODULES(LUA, lua, [
96 - AC_DEFINE([HAVE_LUA], [1], [liblua])
97 - AC_DEFINE([HAVE_LUA_H], [1], [lua.h])
107 AC_CHECK_FUNCS([dup2 getcwd inet_ntoa inet_ntop memset mmap munmap strchr \
108 - strdup strerror strstr strtol sendfile getopt socket \
109 - gethostbyname poll sigtimedwait epoll_ctl getrlimit chroot \
110 + strdup strerror strstr strtol sendfile getopt socket lstat \
111 + gethostbyname poll sigtimedwait epoll_ctl getrlimit chroot strptime \
112 getuid select signal pathconf madvise posix_fadvise posix_madvise \
113 writev sigaction sendfile64 send_file kqueue port_create localtime_r])
118 if test "${GCC}" = "yes"; then
119 - CFLAGS="${CFLAGS} -Wall -W -Wshadow -pedantic"
120 + CFLAGS="${CFLAGS} -Wall -W -Wshadow -pedantic -std=gnu99"
128 -do_build="mod_cgi mod_fastcgi mod_proxy mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfiles mod_userdir mod_webdav mod_staticfile mod_scgi"
129 +do_build="mod_cgi mod_fastcgi mod_proxy mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfiles mod_userdir mod_webdav mod_staticfile mod_scgi mod_flv_streaming"
131 plugins="mod_rewrite mod_redirect mod_ssi mod_trigger_b4_dl"
132 features="regex-conditionals"
134 disable_feature="$disable_feature $features"
137 +features="webdav-locks"
138 +if test "x$UUID_LIB" \!= x; then
139 + enable_feature="$enable_feature $features"
141 + disable_feature="$disable_feature $features"
148 --- ../lighttpd-1.4.11/cygwin/lighttpd.README 2006-03-07 14:22:19.000000000 +0200
149 +++ lighttpd-1.5.0/cygwin/lighttpd.README 2006-09-07 01:00:40.000000000 +0300
152 -------------------------------------------
\r
153 -A fast, secure and flexible webserver
\r
155 -Runtime requirements:
\r
156 - cygwin-1.5.10 or newer
\r
157 - crypt-1.1 or newer
\r
158 - libbz2_1-1.0.2 or newer
\r
159 - libpcre0-4.5 or newer
\r
160 - openssl-0.9.7d or newer
\r
161 - zlib-1.2.1 or newer
\r
163 -Build requirements:
\r
164 - cygwin-1.5.10 or newer
\r
165 - gcc-3.3.1-3 or newer
\r
166 - binutils-20030901-1 or newer
\r
175 -Canonical homepage:
\r
176 - http://jan.kneschke.de/projects/lighttpd/
\r
178 -Canonical download:
\r
179 - http://jan.kneschke.de/projects/lighttpd/download
\r
181 -------------------------------------
\r
183 -Build instructions:
\r
184 - unpack lighttpd-1.4.11-<REL>-src.tar.bz2
\r
185 - if you use setup to install this src package, it will be
\r
186 - unpacked under /usr/src automatically
\r
188 - ./lighttpd-1.4.11-<REL>.sh all
\r
191 - /usr/src/lighttpd-1.4.11-<REL>.tar.bz2
\r
192 - /usr/src/lighttpd-1.4.11-<REL>-src.tar.bz2
\r
194 -Or use './lighttpd-1.4.11-<REL>.sh prep' to get a patched source directory
\r
196 --------------------------------------------
\r
198 -Files included in the binary distribution:
\r
200 - /etc/lighttpd/lighttpd.conf.default
\r
201 - /usr/lib/cyglightcomp.dll
\r
202 - /usr/lib/lighttpd/mod_access.dll
\r
203 - /usr/lib/lighttpd/mod_accesslog.dll
\r
204 - /usr/lib/lighttpd/mod_auth.dll
\r
205 - /usr/lib/lighttpd/mod_cgi.dll
\r
206 - /usr/lib/lighttpd/mod_compress.dll
\r
207 - /usr/lib/lighttpd/mod_evhost.dll
\r
208 - /usr/lib/lighttpd/mod_expire.dll
\r
209 - /usr/lib/lighttpd/mod_fastcgi.dll
\r
210 - /usr/lib/lighttpd/mod_httptls.dll
\r
211 - /usr/lib/lighttpd/mod_maps.dll
\r
212 - /usr/lib/lighttpd/mod_proxy.dll
\r
213 - /usr/lib/lighttpd/mod_redirect.dll
\r
214 - /usr/lib/lighttpd/mod_rewrite.dll
\r
215 - /usr/lib/lighttpd/mod_rrdtool.dll
\r
216 - /usr/lib/lighttpd/mod_secdownload.dll
\r
217 - /usr/lib/lighttpd/mod_simple_vhost.dll
\r
218 - /usr/lib/lighttpd/mod_ssi.dll
\r
219 - /usr/lib/lighttpd/mod_status.dll
\r
220 - /usr/lib/lighttpd/mod_usertrack.dll
\r
221 - /usr/sbin/lighttpd.exe
\r
222 - /usr/share/doc/Cygwin/lighttpd-1.3.0.README
\r
223 - /usr/share/doc/lighttpd-1.3.0/accesslog.txt
\r
224 - /usr/share/doc/lighttpd-1.3.0/authentification.txt
\r
225 - /usr/share/doc/lighttpd-1.3.0/AUTHORS
\r
226 - /usr/share/doc/lighttpd-1.3.0/cgi.txt
\r
227 - /usr/share/doc/lighttpd-1.3.0/ChangeLog
\r
228 - /usr/share/doc/lighttpd-1.3.0/compress.txt
\r
229 - /usr/share/doc/lighttpd-1.3.0/configuration.txt
\r
230 - /usr/share/doc/lighttpd-1.3.0/COPYING
\r
231 - /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
\r
232 - /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
\r
233 - /usr/share/doc/lighttpd-1.3.0/features.txt
\r
234 - /usr/share/doc/lighttpd-1.3.0/INSTALL
\r
235 - /usr/share/doc/lighttpd-1.3.0/NEWS
\r
236 - /usr/share/doc/lighttpd-1.3.0/performance.txt
\r
237 - /usr/share/doc/lighttpd-1.3.0/plugins.txt
\r
238 - /usr/share/doc/lighttpd-1.3.0/proxy.txt
\r
239 - /usr/share/doc/lighttpd-1.3.0/README
\r
240 - /usr/share/doc/lighttpd-1.3.0/redirect.txt
\r
241 - /usr/share/doc/lighttpd-1.3.0/rewrite.txt
\r
242 - /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
\r
243 - /usr/share/doc/lighttpd-1.3.0/secdownload.txt
\r
244 - /usr/share/doc/lighttpd-1.3.0/security.txt
\r
245 - /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
\r
246 - /usr/share/doc/lighttpd-1.3.0/skeleton.txt
\r
247 - /usr/share/doc/lighttpd-1.3.0/ssi.txt
\r
248 - /usr/share/doc/lighttpd-1.3.0/state.txt
\r
249 - /usr/share/man/man1/lighttpd.1.gz
\r
251 -------------------
\r
255 ----------- lighttpd-1.3.1-1 -----------
\r
259 ----------- lighttpd-1.3.0-1 -----------
\r
262 -Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
\r
263 -Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
\r
266 +------------------------------------------
267 +A fast, secure and flexible webserver
269 +Runtime requirements:
270 + cygwin-1.5.10 or newer
272 + libbz2_1-1.0.2 or newer
273 + libpcre0-4.5 or newer
274 + openssl-0.9.7d or newer
275 + zlib-1.2.1 or newer
278 + cygwin-1.5.10 or newer
279 + gcc-3.3.1-3 or newer
280 + binutils-20030901-1 or newer
290 + http://jan.kneschke.de/projects/lighttpd/
293 + http://jan.kneschke.de/projects/lighttpd/download
295 +------------------------------------
298 + unpack lighttpd-1.5.0-<REL>-src.tar.bz2
299 + if you use setup to install this src package, it will be
300 + unpacked under /usr/src automatically
302 + ./lighttpd-1.5.0-<REL>.sh all
305 + /usr/src/lighttpd-1.5.0-<REL>.tar.bz2
306 + /usr/src/lighttpd-1.5.0-<REL>-src.tar.bz2
308 +Or use './lighttpd-1.5.0-<REL>.sh prep' to get a patched source directory
310 +-------------------------------------------
312 +Files included in the binary distribution:
314 + /etc/lighttpd/lighttpd.conf.default
315 + /usr/lib/cyglightcomp.dll
316 + /usr/lib/lighttpd/mod_access.dll
317 + /usr/lib/lighttpd/mod_accesslog.dll
318 + /usr/lib/lighttpd/mod_auth.dll
319 + /usr/lib/lighttpd/mod_cgi.dll
320 + /usr/lib/lighttpd/mod_compress.dll
321 + /usr/lib/lighttpd/mod_evhost.dll
322 + /usr/lib/lighttpd/mod_expire.dll
323 + /usr/lib/lighttpd/mod_fastcgi.dll
324 + /usr/lib/lighttpd/mod_httptls.dll
325 + /usr/lib/lighttpd/mod_maps.dll
326 + /usr/lib/lighttpd/mod_proxy.dll
327 + /usr/lib/lighttpd/mod_redirect.dll
328 + /usr/lib/lighttpd/mod_rewrite.dll
329 + /usr/lib/lighttpd/mod_rrdtool.dll
330 + /usr/lib/lighttpd/mod_secdownload.dll
331 + /usr/lib/lighttpd/mod_simple_vhost.dll
332 + /usr/lib/lighttpd/mod_ssi.dll
333 + /usr/lib/lighttpd/mod_status.dll
334 + /usr/lib/lighttpd/mod_usertrack.dll
335 + /usr/sbin/lighttpd.exe
336 + /usr/share/doc/Cygwin/lighttpd-1.3.0.README
337 + /usr/share/doc/lighttpd-1.3.0/accesslog.txt
338 + /usr/share/doc/lighttpd-1.3.0/authentification.txt
339 + /usr/share/doc/lighttpd-1.3.0/AUTHORS
340 + /usr/share/doc/lighttpd-1.3.0/cgi.txt
341 + /usr/share/doc/lighttpd-1.3.0/ChangeLog
342 + /usr/share/doc/lighttpd-1.3.0/compress.txt
343 + /usr/share/doc/lighttpd-1.3.0/configuration.txt
344 + /usr/share/doc/lighttpd-1.3.0/COPYING
345 + /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
346 + /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
347 + /usr/share/doc/lighttpd-1.3.0/features.txt
348 + /usr/share/doc/lighttpd-1.3.0/INSTALL
349 + /usr/share/doc/lighttpd-1.3.0/NEWS
350 + /usr/share/doc/lighttpd-1.3.0/performance.txt
351 + /usr/share/doc/lighttpd-1.3.0/plugins.txt
352 + /usr/share/doc/lighttpd-1.3.0/proxy.txt
353 + /usr/share/doc/lighttpd-1.3.0/README
354 + /usr/share/doc/lighttpd-1.3.0/redirect.txt
355 + /usr/share/doc/lighttpd-1.3.0/rewrite.txt
356 + /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
357 + /usr/share/doc/lighttpd-1.3.0/secdownload.txt
358 + /usr/share/doc/lighttpd-1.3.0/security.txt
359 + /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
360 + /usr/share/doc/lighttpd-1.3.0/skeleton.txt
361 + /usr/share/doc/lighttpd-1.3.0/ssi.txt
362 + /usr/share/doc/lighttpd-1.3.0/state.txt
363 + /usr/share/man/man1/lighttpd.1.gz
369 +---------- lighttpd-1.3.1-1 -----------
373 +---------- lighttpd-1.3.0-1 -----------
376 +Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
377 +Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
379 --- ../lighttpd-1.4.11/cygwin/lighttpd.README.in 2005-08-11 01:26:59.000000000 +0300
380 +++ lighttpd-1.5.0/cygwin/lighttpd.README.in 2006-07-16 00:26:04.000000000 +0300
383 -------------------------------------------
\r
384 -A fast, secure and flexible webserver
\r
386 -Runtime requirements:
\r
387 - cygwin-1.5.10 or newer
\r
388 - crypt-1.1 or newer
\r
389 - libbz2_1-1.0.2 or newer
\r
390 - libpcre0-4.5 or newer
\r
391 - openssl-0.9.7d or newer
\r
392 - zlib-1.2.1 or newer
\r
394 -Build requirements:
\r
395 - cygwin-1.5.10 or newer
\r
396 - gcc-3.3.1-3 or newer
\r
397 - binutils-20030901-1 or newer
\r
406 -Canonical homepage:
\r
407 - http://jan.kneschke.de/projects/lighttpd/
\r
409 -Canonical download:
\r
410 - http://jan.kneschke.de/projects/lighttpd/download
\r
412 -------------------------------------
\r
414 -Build instructions:
\r
415 - unpack lighttpd-@VERSION@-<REL>-src.tar.bz2
\r
416 - if you use setup to install this src package, it will be
\r
417 - unpacked under /usr/src automatically
\r
419 - ./lighttpd-@VERSION@-<REL>.sh all
\r
422 - /usr/src/lighttpd-@VERSION@-<REL>.tar.bz2
\r
423 - /usr/src/lighttpd-@VERSION@-<REL>-src.tar.bz2
\r
425 -Or use './lighttpd-@VERSION@-<REL>.sh prep' to get a patched source directory
\r
427 --------------------------------------------
\r
429 -Files included in the binary distribution:
\r
431 - /etc/lighttpd/lighttpd.conf.default
\r
432 - /usr/lib/cyglightcomp.dll
\r
433 - /usr/lib/lighttpd/mod_access.dll
\r
434 - /usr/lib/lighttpd/mod_accesslog.dll
\r
435 - /usr/lib/lighttpd/mod_auth.dll
\r
436 - /usr/lib/lighttpd/mod_cgi.dll
\r
437 - /usr/lib/lighttpd/mod_compress.dll
\r
438 - /usr/lib/lighttpd/mod_evhost.dll
\r
439 - /usr/lib/lighttpd/mod_expire.dll
\r
440 - /usr/lib/lighttpd/mod_fastcgi.dll
\r
441 - /usr/lib/lighttpd/mod_httptls.dll
\r
442 - /usr/lib/lighttpd/mod_maps.dll
\r
443 - /usr/lib/lighttpd/mod_proxy.dll
\r
444 - /usr/lib/lighttpd/mod_redirect.dll
\r
445 - /usr/lib/lighttpd/mod_rewrite.dll
\r
446 - /usr/lib/lighttpd/mod_rrdtool.dll
\r
447 - /usr/lib/lighttpd/mod_secdownload.dll
\r
448 - /usr/lib/lighttpd/mod_simple_vhost.dll
\r
449 - /usr/lib/lighttpd/mod_ssi.dll
\r
450 - /usr/lib/lighttpd/mod_status.dll
\r
451 - /usr/lib/lighttpd/mod_usertrack.dll
\r
452 - /usr/sbin/lighttpd.exe
\r
453 - /usr/share/doc/Cygwin/lighttpd-1.3.0.README
\r
454 - /usr/share/doc/lighttpd-1.3.0/accesslog.txt
\r
455 - /usr/share/doc/lighttpd-1.3.0/authentification.txt
\r
456 - /usr/share/doc/lighttpd-1.3.0/AUTHORS
\r
457 - /usr/share/doc/lighttpd-1.3.0/cgi.txt
\r
458 - /usr/share/doc/lighttpd-1.3.0/ChangeLog
\r
459 - /usr/share/doc/lighttpd-1.3.0/compress.txt
\r
460 - /usr/share/doc/lighttpd-1.3.0/configuration.txt
\r
461 - /usr/share/doc/lighttpd-1.3.0/COPYING
\r
462 - /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
\r
463 - /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
\r
464 - /usr/share/doc/lighttpd-1.3.0/features.txt
\r
465 - /usr/share/doc/lighttpd-1.3.0/INSTALL
\r
466 - /usr/share/doc/lighttpd-1.3.0/NEWS
\r
467 - /usr/share/doc/lighttpd-1.3.0/performance.txt
\r
468 - /usr/share/doc/lighttpd-1.3.0/plugins.txt
\r
469 - /usr/share/doc/lighttpd-1.3.0/proxy.txt
\r
470 - /usr/share/doc/lighttpd-1.3.0/README
\r
471 - /usr/share/doc/lighttpd-1.3.0/redirect.txt
\r
472 - /usr/share/doc/lighttpd-1.3.0/rewrite.txt
\r
473 - /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
\r
474 - /usr/share/doc/lighttpd-1.3.0/secdownload.txt
\r
475 - /usr/share/doc/lighttpd-1.3.0/security.txt
\r
476 - /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
\r
477 - /usr/share/doc/lighttpd-1.3.0/skeleton.txt
\r
478 - /usr/share/doc/lighttpd-1.3.0/ssi.txt
\r
479 - /usr/share/doc/lighttpd-1.3.0/state.txt
\r
480 - /usr/share/man/man1/lighttpd.1.gz
\r
482 -------------------
\r
486 ----------- lighttpd-1.3.1-1 -----------
\r
490 ----------- lighttpd-1.3.0-1 -----------
\r
493 -Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
\r
494 -Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
\r
497 +------------------------------------------
498 +A fast, secure and flexible webserver
500 +Runtime requirements:
501 + cygwin-1.5.10 or newer
503 + libbz2_1-1.0.2 or newer
504 + libpcre0-4.5 or newer
505 + openssl-0.9.7d or newer
506 + zlib-1.2.1 or newer
509 + cygwin-1.5.10 or newer
510 + gcc-3.3.1-3 or newer
511 + binutils-20030901-1 or newer
521 + http://jan.kneschke.de/projects/lighttpd/
524 + http://jan.kneschke.de/projects/lighttpd/download
526 +------------------------------------
529 + unpack lighttpd-@VERSION@-<REL>-src.tar.bz2
530 + if you use setup to install this src package, it will be
531 + unpacked under /usr/src automatically
533 + ./lighttpd-@VERSION@-<REL>.sh all
536 + /usr/src/lighttpd-@VERSION@-<REL>.tar.bz2
537 + /usr/src/lighttpd-@VERSION@-<REL>-src.tar.bz2
539 +Or use './lighttpd-@VERSION@-<REL>.sh prep' to get a patched source directory
541 +-------------------------------------------
543 +Files included in the binary distribution:
545 + /etc/lighttpd/lighttpd.conf.default
546 + /usr/lib/cyglightcomp.dll
547 + /usr/lib/lighttpd/mod_access.dll
548 + /usr/lib/lighttpd/mod_accesslog.dll
549 + /usr/lib/lighttpd/mod_auth.dll
550 + /usr/lib/lighttpd/mod_cgi.dll
551 + /usr/lib/lighttpd/mod_compress.dll
552 + /usr/lib/lighttpd/mod_evhost.dll
553 + /usr/lib/lighttpd/mod_expire.dll
554 + /usr/lib/lighttpd/mod_fastcgi.dll
555 + /usr/lib/lighttpd/mod_httptls.dll
556 + /usr/lib/lighttpd/mod_maps.dll
557 + /usr/lib/lighttpd/mod_proxy.dll
558 + /usr/lib/lighttpd/mod_redirect.dll
559 + /usr/lib/lighttpd/mod_rewrite.dll
560 + /usr/lib/lighttpd/mod_rrdtool.dll
561 + /usr/lib/lighttpd/mod_secdownload.dll
562 + /usr/lib/lighttpd/mod_simple_vhost.dll
563 + /usr/lib/lighttpd/mod_ssi.dll
564 + /usr/lib/lighttpd/mod_status.dll
565 + /usr/lib/lighttpd/mod_usertrack.dll
566 + /usr/sbin/lighttpd.exe
567 + /usr/share/doc/Cygwin/lighttpd-1.3.0.README
568 + /usr/share/doc/lighttpd-1.3.0/accesslog.txt
569 + /usr/share/doc/lighttpd-1.3.0/authentification.txt
570 + /usr/share/doc/lighttpd-1.3.0/AUTHORS
571 + /usr/share/doc/lighttpd-1.3.0/cgi.txt
572 + /usr/share/doc/lighttpd-1.3.0/ChangeLog
573 + /usr/share/doc/lighttpd-1.3.0/compress.txt
574 + /usr/share/doc/lighttpd-1.3.0/configuration.txt
575 + /usr/share/doc/lighttpd-1.3.0/COPYING
576 + /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
577 + /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
578 + /usr/share/doc/lighttpd-1.3.0/features.txt
579 + /usr/share/doc/lighttpd-1.3.0/INSTALL
580 + /usr/share/doc/lighttpd-1.3.0/NEWS
581 + /usr/share/doc/lighttpd-1.3.0/performance.txt
582 + /usr/share/doc/lighttpd-1.3.0/plugins.txt
583 + /usr/share/doc/lighttpd-1.3.0/proxy.txt
584 + /usr/share/doc/lighttpd-1.3.0/README
585 + /usr/share/doc/lighttpd-1.3.0/redirect.txt
586 + /usr/share/doc/lighttpd-1.3.0/rewrite.txt
587 + /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
588 + /usr/share/doc/lighttpd-1.3.0/secdownload.txt
589 + /usr/share/doc/lighttpd-1.3.0/security.txt
590 + /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
591 + /usr/share/doc/lighttpd-1.3.0/skeleton.txt
592 + /usr/share/doc/lighttpd-1.3.0/ssi.txt
593 + /usr/share/doc/lighttpd-1.3.0/state.txt
594 + /usr/share/man/man1/lighttpd.1.gz
600 +---------- lighttpd-1.3.1-1 -----------
604 +---------- lighttpd-1.3.0-1 -----------
607 +Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
608 +Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
610 --- ../lighttpd-1.4.11/doc/authentication.txt 2006-01-12 20:34:26.000000000 +0200
611 +++ lighttpd-1.5.0/doc/authentication.txt 2006-07-16 00:26:05.000000000 +0300
615 :Author: Jan Kneschke
617 -:Revision: $Revision$
619 +:Revision: $Revision$
622 The auth module provides ...
623 --- ../lighttpd-1.4.11/doc/compress.txt 2005-08-11 01:26:16.000000000 +0300
624 +++ lighttpd-1.5.0/doc/compress.txt 2006-07-16 00:26:05.000000000 +0300
628 Output compression reduces the network load and can improve the overall
629 -throughput of the webserver.
630 +throughput of the webserver. All major http-clients support compression by
631 +announcing it in the Accept-Encoding header. This is used to negotiate the
632 +most suitable compression method. We support deflate, gzip and bzip2.
634 -Only static content is supported up to now.
635 +deflate (RFC1950, RFC1951) and gzip (RFC1952) depend on zlib while bzip2
636 +depends on libbzip2. bzip2 is only supported by lynx and some other console
639 -The server negotiates automaticly which compression method is used.
640 -Supported are gzip, deflate, bzip.
641 +Currently we limit to compression support to static files.
646 +mod_compress can stored compressed files on disk to optimized the compression
647 +on a second request away. As soon as compress.cache-dir is set the files are
650 +The names of the cache files are made of the filename, the compression method
651 +and the etag associated to the file.
653 +Cleaning the cache is left to the user. A cron job deleting files older than
654 +10 days should do fine.
659 +The module limits the compression of files to files larger than 128 Byte and
660 +smaller than 128 MByte.
662 +The lower limit is set as small files tend to become larger by compressing due
663 +to the compression headers, the upper limit is set to work sensable with
664 +memory and cpu-time.
669 Default: not set, compress the file for every request
672 - mimetypes where might get compressed
673 + mimetypes which might get compressed
677 compress.filetype = ("text/plain", "text/html")
679 + Keep in mind that compressed JavaScript and CSS files are broken in some
684 +compress.max-file-size
685 + maximum size of the original file to be compressed kBytes.
687 + This is meant to protect the server against DoSing as compressing large
688 + (let's say 1Gbyte) takes a lot of time and would delay the whole operation
691 + There is a hard upper limit of 128Mbyte.
693 + Default: unlimited (== hard-limit of 128MByte)
695 Compressing Dynamic Content
696 ===========================
698 --- ../lighttpd-1.4.11/doc/configuration.txt 2006-03-09 02:10:40.000000000 +0200
699 +++ lighttpd-1.5.0/doc/configuration.txt 2006-07-16 00:26:05.000000000 +0300
703 :Author: Jan Kneschke
705 -:Revision: $Revision$
707 +:Revision: $Revision$
710 the layout of the configuration file
713 debug.log-request-handling
716 +debug.log-condition-handling
719 +debug.log-condition-cache-handling
720 + for developers only
722 --- ../lighttpd-1.4.11/doc/fastcgi.txt 2006-02-16 17:03:52.000000000 +0200
723 +++ lighttpd-1.5.0/doc/fastcgi.txt 2006-07-16 00:26:05.000000000 +0300
725 PHP can extract PATH_INFO from it (default: disabled)
726 :"disable-time": time to wait before a disabled backend is checked
728 - :"allow-x-send-file": controls if X-LIGHTTPD-send-file headers
730 + :"allow-x-send-file": controls if X-LIGHTTPD-send-file and X-Sendfile
731 + headers are allowed
735 --- ../lighttpd-1.4.11/doc/lighttpd.conf 2006-03-04 14:41:12.000000000 +0200
736 +++ lighttpd-1.5.0/doc/lighttpd.conf 2006-07-16 00:26:05.000000000 +0300
737 @@ -172,10 +172,11 @@
738 #dir-listing.activate = "enable"
741 -#debug.log-request-header = "enable"
742 -#debug.log-response-header = "enable"
743 -#debug.log-request-handling = "enable"
744 -#debug.log-file-not-found = "enable"
745 +#debug.log-request-header = "enable"
746 +#debug.log-response-header = "enable"
747 +#debug.log-request-handling = "enable"
748 +#debug.log-file-not-found = "enable"
749 +#debug.log-condition-handling = "enable"
751 ### only root can use these options
753 --- ../lighttpd-1.4.11/doc/performance.txt 2006-02-02 13:01:08.000000000 +0200
754 +++ lighttpd-1.5.0/doc/performance.txt 2006-07-16 00:26:05.000000000 +0300
757 server.stat-cache-engine = "fam" # either fam, simple or disabled
759 +See http://oss.sgi.com/projects/fam/faq.html for information about FAM.
760 +See http://www.gnome.org/~veillard/gamin/overview.html for information about gamin.
762 Platform-Specific Notes
763 =======================
764 --- ../lighttpd-1.4.11/doc/secdownload.txt 2005-12-20 15:58:58.000000000 +0200
765 +++ lighttpd-1.5.0/doc/secdownload.txt 2006-07-16 00:26:05.000000000 +0300
767 $secret = "verysecret";
768 $uri_prefix = "/dl/";
771 + # filename, make sure it's started with a "/" or you'll get 404 in the browser
772 $f = "/secret-file.txt";
775 --- ../lighttpd-1.4.11/lighttpd.spec 2006-03-07 14:22:18.000000000 +0200
776 +++ lighttpd-1.5.0/lighttpd.spec 2006-09-07 01:00:40.000000000 +0300
778 Summary: A fast webserver with minimal memory-footprint (lighttpd)
783 Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-%version.tar.gz
784 Packager: Jan Kneschke <jan@kneschke.de>
785 --- ../lighttpd-1.4.11/openwrt/control 2006-03-07 14:22:19.000000000 +0200
786 +++ lighttpd-1.5.0/openwrt/control 2006-09-07 01:00:41.000000000 +0300
792 Maintainer: Jan Kneschke <jan@kneschke.de>
793 -Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.11.tar.gz
794 +Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.5.0.tar.gz
798 --- ../lighttpd-1.4.11/openwrt/lighttpd.mk 2006-03-07 14:22:19.000000000 +0200
799 +++ lighttpd-1.5.0/openwrt/lighttpd.mk 2006-09-07 01:00:41.000000000 +0300
802 # For this example we'll use a fairly simple package that compiles easily
803 # and has sources available for download at sourceforge
804 -LIGHTTPD=lighttpd-1.4.11
805 +LIGHTTPD=lighttpd-1.5.0
806 LIGHTTPD_TARGET=.built
807 LIGHTTPD_DIR=$(BUILD_DIR)/$(LIGHTTPD)
808 LIGHTTPD_IPK=$(BUILD_DIR)/$(LIGHTTPD)_mipsel.ipk
809 --- ../lighttpd-1.4.11/src/Makefile.am 2006-03-07 14:20:20.000000000 +0200
810 +++ lighttpd-1.5.0/src/Makefile.am 2006-09-07 00:57:05.000000000 +0300
813 configparser.y: lemon
814 mod_ssi_exprparser.y: lemon
815 +http_resp_parser.y: lemon
816 +http_req_parser.y: lemon
817 +http_req_range_parser.y: lemon
819 configparser.c configparser.h: configparser.y
821 $(LEMON) -q $(srcdir)/configparser.y $(srcdir)/lempar.c
823 +http_resp_parser.c http_resp_parser.h: http_resp_parser.y
824 + rm -f http_resp_parser.h
825 + $(LEMON) -q $(srcdir)/http_resp_parser.y $(srcdir)/lempar.c
827 +http_req_parser.c http_req_parser.h: http_req_parser.y
828 + rm -f http_req_parser.h
829 + $(LEMON) -q $(srcdir)/http_req_parser.y $(srcdir)/lempar.c
831 +http_req_range_parser.c http_req_range_parser.h: http_req_range_parser.y
832 + rm -f http_req_parser.h
833 + $(LEMON) -q $(srcdir)/http_req_range_parser.y $(srcdir)/lempar.c
835 mod_ssi_exprparser.c mod_ssi_exprparser.h: mod_ssi_exprparser.y
836 rm -f mod_ssi_exprparser.h
837 $(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c
840 configfile.c: configparser.h
841 mod_ssi_expr.c: mod_ssi_exprparser.h
842 +http_resp.c: http_resp_parser.h
843 +http_req.c: http_req_parser.h
844 +http_req_range.c: http_req_range_parser.h
846 common_src=buffer.c log.c \
848 - http_chunk.c stream.c fdevent.c \
849 + stream.c fdevent.c \
850 stat_cache.c plugin.c joblist.c etag.c array.c \
851 data_string.c data_count.c data_array.c \
852 data_integer.c md5.c data_fastcgi.c \
854 fdevent_solaris_devpoll.c fdevent_freebsd_kqueue.c \
855 data_config.c bitset.c \
856 inet_ntop_cache.c crc32.c \
857 - connections-glue.c \
858 - configfile-glue.c \
859 + connections-glue.c iosocket.c \
860 + configfile-glue.c status_counter.c \
862 network_write.c network_linux_sendfile.c \
863 network_freebsd_sendfile.c network_writev.c \
864 network_solaris_sendfilev.c network_openssl.c \
867 + http_resp.c http_resp_parser.c \
868 + http_req.c http_req_parser.c \
869 + http_req_range.c http_req_range_parser.c
871 src = server.c response.c connections.c network.c \
872 configfile.c configparser.c request.c proc_open.c
874 mod_flv_streaming_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
875 mod_flv_streaming_la_LIBADD = $(common_libadd)
877 +lib_LTLIBRARIES += mod_uploadprogress.la
878 +mod_uploadprogress_la_SOURCES = mod_uploadprogress.c
879 +mod_uploadprogress_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
880 +mod_uploadprogress_la_LIBADD = $(common_libadd)
882 lib_LTLIBRARIES += mod_evasive.la
883 mod_evasive_la_SOURCES = mod_evasive.c
884 mod_evasive_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
887 lib_LTLIBRARIES += mod_webdav.la
888 mod_webdav_la_SOURCES = mod_webdav.c
889 -mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS)
890 +mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS)
891 mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
892 -mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS)
893 +mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) $(UUID_LIB)
895 lib_LTLIBRARIES += mod_cml.la
896 mod_cml_la_SOURCES = mod_cml.c mod_cml_lua.c mod_cml_funcs.c
898 mod_mysql_vhost_la_LIBADD = $(MYSQL_LIBS) $(common_libadd)
899 mod_mysql_vhost_la_CPPFLAGS = $(MYSQL_INCLUDE)
901 +lib_LTLIBRARIES += mod_sql_vhost_core.la
902 +mod_sql_vhost_core_la_SOURCES = mod_sql_vhost_core.c
903 +mod_sql_vhost_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
904 +mod_sql_vhost_core_la_LIBADD = $(common_libadd)
906 lib_LTLIBRARIES += mod_cgi.la
907 mod_cgi_la_SOURCES = mod_cgi.c
908 mod_cgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
910 mod_proxy_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
911 mod_proxy_la_LIBADD = $(common_libadd)
913 +lib_LTLIBRARIES += mod_proxy_core.la
914 +mod_proxy_core_la_SOURCES = mod_proxy_core.c mod_proxy_core_pool.c \
915 + mod_proxy_core_backend.c mod_proxy_core_address.c \
916 + mod_proxy_core_backlog.c mod_proxy_core_rewrites.c \
917 + mod_proxy_backend_http.c mod_proxy_backend_fastcgi.c
918 +mod_proxy_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
919 +mod_proxy_core_la_LIBADD = $(common_libadd) $(PCRE_LIB)
922 lib_LTLIBRARIES += mod_ssi.la
923 mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c
924 mod_ssi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
927 hdr = server.h buffer.h network.h log.h keyvalue.h \
928 response.h request.h fastcgi.h chunk.h \
929 - settings.h http_chunk.h http_auth_digest.h \
930 + settings.h http_auth_digest.h \
931 md5.h http_auth.h stream.h \
932 fdevent.h connections.h base.h stat_cache.h \
933 plugin.h mod_auth.h \
935 mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
936 configparser.h mod_ssi_exprparser.h \
937 sys-mmap.h sys-socket.h mod_cml.h mod_cml_funcs.h \
938 - splaytree.h proc_open.h
939 + splaytree.h proc_open.h mod_sql_vhost_core.h \
940 + sys-files.h sys-process.h sys-strings.h \
941 + iosocket.h array-static.h \
942 + mod_proxy_core_address.h \
943 + mod_proxy_core_backend.h \
944 + mod_proxy_core_backlog.h \
946 + mod_proxy_core_pool.h \
947 + mod_proxy_core_rewrites.h \
948 + mod_proxy_backend_http.h \
949 + mod_proxy_backend_fastcgi.h \
952 + http_req_parser.h \
954 + http_req_range_parser.h \
956 + http_resp_parser.h \
959 DEFS= @DEFS@ -DLIBRARY_DIR="\"$(libdir)\""
964 noinst_HEADERS = $(hdr)
965 -EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c
966 +EXTRA_DIST = mod_skeleton.c \
968 + mod_ssi_exprparser.y \
970 + http_resp_parser.y \
971 + http_req_parser.y \
972 + http_req_range_parser.y
973 --- ../lighttpd-1.4.11/src/array-static.h 1970-01-01 03:00:00.000000000 +0300
974 +++ lighttpd-1.5.0/src/array-static.h 2006-07-18 13:03:40.000000000 +0300
976 +#ifndef _ARRAY_STATIC_H_
977 +#define _ARRAY_STATIC_H_
979 +/* define a generic array of <type>
982 +#define ARRAY_STATIC_DEF(name, type, extra) \
990 +/* all append operations need a 'resize' for the +1 */
992 +#define ARRAY_STATIC_PREPARE_APPEND(a) \
993 + if (a->size == 0) { \
995 + a->ptr = malloc(a->size * sizeof(*(a->ptr))); \
996 + } else if (a->size == a->used) { \
998 + a->ptr = realloc(a->ptr, a->size * sizeof(*(a->ptr))); \
1001 +#define FOREACH(array, element, func) \
1002 +do { size_t _i; for (_i = 0; _i < array->used; _i++) { void *element = array->ptr[_i]; func; } } while(0);
1004 +#define STRUCT_INIT(type, var) \
1006 + var = calloc(1, sizeof(*var))
1009 --- ../lighttpd-1.4.11/src/array.c 2005-11-18 13:58:32.000000000 +0200
1010 +++ lighttpd-1.5.0/src/array.c 2006-07-16 00:26:03.000000000 +0300
1013 array *array_init(void) {
1017 a = calloc(1, sizeof(*a));
1021 a->next_power_of_2 = 1;
1028 void array_free(array *a) {
1033 if (!a->is_weakref) {
1034 for (i = 0; i < a->size; i++) {
1035 if (a->data[i]) a->data[i]->free(a->data[i]);
1040 if (a->data) free(a->data);
1041 if (a->sorted) free(a->sorted);
1047 void array_reset(array *a) {
1052 if (!a->is_weakref) {
1053 for (i = 0; i < a->used; i++) {
1054 a->data[i]->reset(a->data[i]);
1063 static int array_get_index(array *a, const char *key, size_t keylen, int *rndx) {
1068 if (key == NULL) return -1;
1071 /* try to find the string */
1072 for (i = pos = a->next_power_of_2 / 2; ; i >>= 1) {
1078 } else if (pos >= (int)a->used) {
1081 cmp = buffer_caseless_compare(key, keylen, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used);
1086 ndx = a->sorted[pos];
1087 @@ -110,46 +110,46 @@
1093 if (rndx) *rndx = pos;
1099 data_unset *array_get_element(array *a, const char *key) {
1103 if (-1 != (ndx = array_get_index(a, key, strlen(key) + 1, NULL))) {
1104 /* found, leave here */
1107 return a->data[ndx];
1115 data_unset *array_get_unused_element(array *a, data_type_t t) {
1116 data_unset *ds = NULL;
1121 if (a->size == 0) return NULL;
1124 if (a->used == a->size) return NULL;
1126 if (a->data[a->used]) {
1127 ds = a->data[a->used];
1130 a->data[a->used] = NULL;
1137 /* replace or insert data, return the old one with the same key */
1138 data_unset *array_replace(array *a, data_unset *du) {
1142 if (-1 == (ndx = array_get_index(a, du->key->ptr, du->key->used, NULL))) {
1143 array_insert_unique(a, du);
1145 @@ -164,13 +164,13 @@
1150 - /* generate unique index if neccesary */
1152 + /* generate unique index if necessary */
1153 if (str->key->used == 0 || str->is_index_key) {
1154 buffer_copy_long(str->key, a->unique_ndx++);
1155 str->is_index_key = 1;
1159 /* try to find the string */
1160 if (-1 != (ndx = array_get_index(a, str->key->ptr, str->key->used, &pos))) {
1161 /* found, leave here */
1162 @@ -181,14 +181,14 @@
1171 if (a->used+1 > INT_MAX) {
1172 /* we can't handle more then INT_MAX entries: see array_get_index() */
1179 a->data = malloc(sizeof(*a->data) * a->size);
1180 @@ -204,27 +204,27 @@
1182 for (j = a->used; j < a->size; j++) a->data[j] = NULL;
1186 ndx = (int) a->used;
1189 a->data[a->used++] = str;
1195 buffer_caseless_compare(str->key->ptr, str->key->used, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used) > 0)) {
1199 - /* move everything on step to the right */
1202 + /* move everything one step to the right */
1204 memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted));
1209 a->sorted[pos] = ndx;
1212 if (a->next_power_of_2 == (size_t)ndx) a->next_power_of_2 <<= 1;
1229 array_print_indent(depth);
1230 fprintf(stderr, ")");
1236 @@ -323,47 +323,47 @@
1248 ds = data_string_init();
1249 buffer_copy_string(ds->key, "abc");
1250 buffer_copy_string(ds->value, "alfrag");
1253 array_insert_unique(a, (data_unset *)ds);
1256 ds = data_string_init();
1257 buffer_copy_string(ds->key, "abc");
1258 buffer_copy_string(ds->value, "hameplman");
1261 array_insert_unique(a, (data_unset *)ds);
1264 ds = data_string_init();
1265 buffer_copy_string(ds->key, "123");
1266 buffer_copy_string(ds->value, "alfrag");
1269 array_insert_unique(a, (data_unset *)ds);
1272 dc = data_count_init();
1273 buffer_copy_string(dc->key, "def");
1276 array_insert_unique(a, (data_unset *)dc);
1279 dc = data_count_init();
1280 buffer_copy_string(dc->key, "def");
1283 array_insert_unique(a, (data_unset *)dc);
1292 fprintf(stderr, "%d\n",
1293 buffer_caseless_compare(CONST_STR_LEN("Content-Type"), CONST_STR_LEN("Content-type")));
1299 --- ../lighttpd-1.4.11/src/array.h 2005-09-23 21:24:18.000000000 +0300
1300 +++ lighttpd-1.5.0/src/array.h 2006-09-07 00:57:05.000000000 +0300
1302 #define DATA_UNSET \
1305 - int is_index_key; /* 1 if key is a array index (autogenerated keys) */ \
1306 + int is_index_key; /* 1 if key is an array index (auto-generated keys) */ \
1307 struct data_unset *(*copy)(const struct data_unset *src); \
1308 void (* free)(struct data_unset *p); \
1309 void (* reset)(struct data_unset *p); \
1326 size_t next_power_of_2;
1327 int is_weakref; /* data is weakref, don't bother the data */
1355 data_array *data_array_init(void);
1357 -typedef enum { CONFIG_COND_UNSET, CONFIG_COND_EQ, CONFIG_COND_MATCH, CONFIG_COND_NE, CONFIG_COND_NOMATCH } config_cond_t;
1359 + * possible compare ops in the configfile parser
1362 + CONFIG_COND_UNSET,
1363 + CONFIG_COND_EQ, /** == */
1364 + CONFIG_COND_MATCH, /** =~ */
1365 + CONFIG_COND_NE, /** != */
1366 + CONFIG_COND_NOMATCH /** !~ */
1369 -#define PATCHES NULL, "SERVERsocket", "HTTPurl", "HTTPhost", "HTTPreferer", "HTTPuseragent", "HTTPcookie", "HTTPremoteip"
1371 + * possible fields to match against
1375 - COMP_SERVER_SOCKET, COMP_HTTP_URL, COMP_HTTP_HOST, COMP_HTTP_REFERER, COMP_HTTP_USERAGENT, COMP_HTTP_COOKIE, COMP_HTTP_REMOTEIP
1376 + COMP_SERVER_SOCKET,
1379 + COMP_HTTP_REFERER,
1380 + COMP_HTTP_USERAGENT,
1382 + COMP_HTTP_REMOTEIP,
1383 + COMP_HTTP_QUERYSTRING
1386 -/* $HTTP["host"] == "incremental.home.kneschke.de" { ... }
1387 +/* $HTTP["host"] == "incremental.home.kneschke.de" { ... }
1388 * for print: comp_key op string
1389 * for compare: comp cond string/regex
1391 @@ -82,15 +100,15 @@
1392 typedef struct _data_config data_config;
1393 struct _data_config {
1408 int context_ndx; /* more or less like an id */
1412 /* for chaining only */
1429 @@ -120,13 +138,13 @@
1435 unsigned short port;
1442 int usage; /* fair-balancing needs the no. of connections active on this host */
1443 int last_used_ndx; /* round robin */
1445 --- ../lighttpd-1.4.11/src/base.h 2006-01-11 16:51:04.000000000 +0200
1446 +++ lighttpd-1.5.0/src/base.h 2006-09-07 00:57:05.000000000 +0300
1450 #include <sys/types.h>
1451 -#include <sys/time.h>
1452 #include <sys/stat.h>
1454 #ifdef HAVE_CONFIG_H
1456 #include "fdevent.h"
1457 #include "sys-socket.h"
1458 #include "splaytree.h"
1460 +#include "http_req.h"
1462 #if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
1463 # define USE_OPENSSL
1464 -# include <openssl/ssl.h>
1465 +# include <openssl/ssl.h>
1473 -#ifndef O_LARGEFILE
1474 -# define O_LARGEFILE 0
1479 # define SIZE_MAX SIZE_T_MAX
1482 /* solaris and NetBSD 1.3.x again */
1483 #if (!defined(HAVE_STDINT_H)) && (!defined(HAVE_INTTYPES_H)) && (!defined(uint32_t))
1484 -# define uint32_t u_int32_t
1485 +/* # define uint32_t u_int32_t */
1486 +typedef unsigned __int32 uint32_t;
1492 #include "settings.h"
1494 -typedef enum { T_CONFIG_UNSET,
1500 - T_CONFIG_DEPRECATED
1501 +typedef enum { T_CONFIG_UNSET,
1507 + T_CONFIG_DEPRECATED,
1508 + T_CONFIG_UNSUPPORTED
1509 } config_values_type_t;
1511 -typedef enum { T_CONFIG_SCOPE_UNSET,
1512 - T_CONFIG_SCOPE_SERVER,
1513 +typedef enum { T_CONFIG_SCOPE_UNSET,
1514 + T_CONFIG_SCOPE_SERVER,
1515 T_CONFIG_SCOPE_CONNECTION
1516 } config_scope_type_t;
1523 config_values_type_t type;
1524 config_scope_type_t scope;
1526 @@ -118,64 +115,38 @@
1533 - struct sockaddr_in6 ipv6;
1535 - struct sockaddr_in ipv4;
1536 -#ifdef HAVE_SYS_UN_H
1537 - struct sockaddr_un un;
1539 - struct sockaddr plain;
1542 -/* fcgi_response_header contains ... */
1543 -#define HTTP_STATUS BV(0)
1544 -#define HTTP_CONNECTION BV(1)
1545 -#define HTTP_CONTENT_LENGTH BV(2)
1546 -#define HTTP_DATE BV(3)
1547 -#define HTTP_LOCATION BV(4)
1551 /* the request-line */
1559 http_method_t http_method;
1560 http_version_t http_version;
1562 - buffer *request_line;
1564 - /* strings to the header */
1565 - buffer *http_host; /* not alloced */
1566 - const char *http_range;
1567 - const char *http_content_type;
1568 - const char *http_if_modified_since;
1569 - const char *http_if_none_match;
1572 + buffer *http_host;
1578 - size_t content_length; /* returned by strtoul() */
1580 + off_t content_length; /* returned by strtoul() */
1582 /* internal representation */
1583 int accept_encoding;
1591 off_t content_length;
1592 - int keep_alive; /* used by the subrequests in proxy, cgi and fcgi to say the subrequest was keep-alive or not */
1594 + int keep_alive; /* used by the subrequests in proxy, cgi and fcgi to say whether the subrequest was keep-alive or not */
1601 HTTP_TRANSFER_ENCODING_IDENTITY, HTTP_TRANSFER_ENCODING_CHUNKED
1602 } transfer_encoding;
1604 @@ -191,21 +162,25 @@
1607 buffer *basedir; /* path = "(basedir)(.*)" */
1610 buffer *doc_root; /* path = doc_root + rel_path */
1635 @@ -215,20 +190,20 @@
1639 - splay_tree *files; /* the nodes of the tree are stat_cache_entry's */
1641 + splay_tree *files; /* the nodes of the tree are stat_cache_entries */
1643 buffer *dir_name; /* for building the dirname from the filename */
1645 splay_tree *dirs; /* the nodes of the tree are fam_dir_entry */
1657 /* virtual-servers */
1658 buffer *document_root;
1659 buffer *server_name;
1662 buffer *dirlist_encoding;
1663 buffer *errorfile_prefix;
1666 unsigned short max_keep_alive_requests;
1667 unsigned short max_keep_alive_idle;
1668 unsigned short max_read_idle;
1669 @@ -244,16 +219,17 @@
1670 unsigned short use_xattr;
1671 unsigned short follow_symlink;
1672 unsigned short range_requests;
1678 unsigned short log_file_not_found;
1679 unsigned short log_request_header;
1680 unsigned short log_request_handling;
1681 unsigned short log_response_header;
1682 unsigned short log_condition_handling;
1685 + unsigned short log_condition_cache_handling;
1689 buffer *ssl_pemfile;
1690 buffer *ssl_ca_file;
1691 @@ -268,22 +244,22 @@
1693 unsigned short global_kbytes_per_second; /* */
1695 - off_t global_bytes_per_second_cnt;
1696 + off_t global_bytes_per_second_cnt;
1697 /* server-wide traffic-shaper
1700 * each context has the counter which is inited once
1701 - * a second by the global_kbytes_per_second config-var
1702 + * per second by the global_kbytes_per_second config-var
1704 * as soon as global_kbytes_per_second gets below 0
1705 * the connected conns are "offline" a little bit
1708 - * we somehow have to loose our "we are writable" signal
1709 + * we somehow have to lose our "we are writable" signal
1714 off_t *global_bytes_per_second_cnt_ptr; /* */
1720 @@ -291,18 +267,19 @@
1722 /* the order of the items should be the same as they are processed
1723 * read before write as we use this later */
1725 - CON_STATE_CONNECT,
1726 - CON_STATE_REQUEST_START,
1728 - CON_STATE_REQUEST_END,
1729 - CON_STATE_READ_POST,
1730 - CON_STATE_HANDLE_REQUEST,
1731 - CON_STATE_RESPONSE_START,
1733 - CON_STATE_RESPONSE_END,
1737 + CON_STATE_CONNECT, /** we are wait for a connect */
1738 + CON_STATE_REQUEST_START, /** after the connect, the request is initialized, keep-alive starts here again */
1739 + CON_STATE_READ_REQUEST_HEADER, /** loop in the read-request-header until the full header is received */
1740 + CON_STATE_VALIDATE_REQUEST_HEADER, /** validate the request-header */
1741 + CON_STATE_HANDLE_REQUEST_HEADER, /** find a handler for the request */
1742 + CON_STATE_READ_REQUEST_CONTENT, /** forward the request content to the handler */
1743 + CON_STATE_HANDLE_RESPONSE_HEADER, /** the backend bounces the response back to the client */
1744 + CON_STATE_WRITE_RESPONSE_HEADER,
1745 + CON_STATE_WRITE_RESPONSE_CONTENT,
1746 + CON_STATE_RESPONSE_END,
1749 } connection_state_t;
1751 typedef enum { COND_RESULT_UNSET, COND_RESULT_FALSE, COND_RESULT_TRUE } cond_result_t;
1752 @@ -315,91 +292,87 @@
1755 connection_state_t state;
1759 time_t read_idle_ts;
1760 time_t close_timeout_ts;
1761 time_t write_request_ts;
1764 time_t connection_start;
1765 time_t request_start;
1768 struct timeval start_tv;
1771 size_t request_count; /* number of requests handled in this connection */
1772 size_t loops_per_request; /* to catch endless loops in a single request
1775 * used by mod_rewrite, mod_fastcgi, ... and others
1776 * this is self-protection
1779 - int fd; /* the FD for this connection */
1780 - int fde_ndx; /* index for the fdevent-handler */
1783 int ndx; /* reverse mapping to server->connection[ndx] */
1790 - int keep_alive; /* only request.c can enable it, all other just disable */
1793 + int keep_alive; /* only request.c can enable it, all others just disable */
1796 - int file_finished;
1798 - chunkqueue *write_queue; /* a large queue for low-level write ( HTTP response ) [ file, mem ] */
1799 - chunkqueue *read_queue; /* a small queue for low-level read ( HTTP request ) [ mem ] */
1800 - chunkqueue *request_content_queue; /* takes request-content into tempfile if necessary [ tempfile, mem ]*/
1803 + chunkqueue *send; /* the response-content without encoding */
1804 + chunkqueue *recv; /* the request-content, without encoding */
1806 + chunkqueue *send_raw; /* the full response (HTTP-Header + compression + chunking ) */
1807 + chunkqueue *recv_raw; /* the full request (HTTP-Header + chunking ) */
1809 int traffic_limit_reached;
1812 off_t bytes_written; /* used by mod_accesslog, mod_rrd */
1813 off_t bytes_written_cur_second; /* used by mod_accesslog, mod_rrd */
1814 off_t bytes_read; /* used by mod_accesslog, mod_rrd */
1822 buffer *dst_addr_buf;
1825 buffer *parse_request;
1826 - unsigned int parsed_response; /* bitfield which contains the important header-fields of the parsed response header */
1829 + http_req *http_req;
1832 - physical physical;
1833 + physical physical;
1840 buffer *authed_user;
1841 array *environment; /* used to pass lighttpd internal stuff to the FastCGI/CGI apps, setenv does that */
1851 connection_type mode;
1854 void **plugin_ctx; /* plugin connection specific config */
1857 specific_config conf; /* global connection specific config */
1858 cond_cache_t *cond_cache;
1861 buffer *server_name;
1865 buffer *error_handler;
1866 int error_handler_saved_status;
1867 int in_error_handler;
1870 void *srv_socket; /* reference to the server-socket (typecast to server_socket) */
1878 @@ -439,55 +412,63 @@
1883 + NETWORK_STATUS_UNSET,
1884 + NETWORK_STATUS_SUCCESS,
1885 + NETWORK_STATUS_FATAL_ERROR,
1886 + NETWORK_STATUS_CONNECTION_CLOSE,
1887 + NETWORK_STATUS_WAIT_FOR_EVENT,
1888 + NETWORK_STATUS_INTERRUPTED
1889 +} network_status_t;
1892 unsigned short port;
1895 - buffer *errorlog_file;
1896 - unsigned short errorlog_use_syslog;
1899 unsigned short dont_daemonize;
1908 buffer *event_handler;
1911 buffer *modules_dir;
1912 buffer *network_backend;
1914 array *upload_tempdirs;
1917 unsigned short max_worker;
1918 unsigned short max_fds;
1919 unsigned short max_conns;
1920 unsigned short max_request_size;
1923 unsigned short log_request_header_on_error;
1924 unsigned short log_state_handling;
1926 - enum { STAT_CACHE_ENGINE_UNSET,
1927 - STAT_CACHE_ENGINE_NONE,
1928 - STAT_CACHE_ENGINE_SIMPLE,
1929 - STAT_CACHE_ENGINE_FAM
1931 + enum { STAT_CACHE_ENGINE_UNSET,
1932 + STAT_CACHE_ENGINE_NONE,
1933 + STAT_CACHE_ENGINE_SIMPLE,
1934 + STAT_CACHE_ENGINE_FAM
1935 } stat_cache_engine;
1936 unsigned short enable_cores;
1938 + buffer *errorlog_file;
1939 + unsigned short errorlog_use_syslog;
1949 buffer *ssl_pemfile;
1950 buffer *ssl_ca_file;
1951 unsigned short use_ipv6;
1952 unsigned short is_ssl;
1961 @@ -495,37 +476,32 @@
1964 server_socket **ptr;
1969 } server_socket_array;
1971 typedef struct server {
1972 server_socket_array srv_sockets;
1974 - /* the errorlog */
1976 - enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } errorlog_mode;
1977 - buffer *errorlog_buf;
1980 fdevents *ev, *ev_ins;
1983 buffer_plugin plugins;
1997 int max_fds; /* max possible fds */
1998 int cur_fds; /* currently used fds */
1999 int want_fds; /* waiting fds */
2000 int sockets_disabled;
2006 @@ -533,13 +509,13 @@
2007 buffer *response_header;
2008 buffer *response_range;
2012 buffer *tmp_chunk_len;
2015 buffer *empty_string; /* is necessary for cond_match */
2017 buffer *cond_check_buf;
2022 inet_ntop_cache_type inet_ntop_cache[INET_NTOP_CACHE_MAX];
2023 @@ -547,59 +523,47 @@
2024 mtime_cache_type mtime_cache[FILE_CACHE_MAX];
2031 time_t last_generated_date_ts;
2032 time_t last_generated_debug_ts;
2036 buffer *ts_debug_str;
2037 buffer *ts_date_str;
2042 array *config_touched;
2045 array *config_context;
2046 specific_config **config_storage;
2049 server_config srvconf;
2051 - int config_deprecated;
2054 + short unsigned config_deprecated;
2055 + short unsigned config_unsupported;
2058 connections *joblist;
2059 connections *fdwaitqueue;
2062 stat_cache *stat_cache;
2065 - * The status array can carry all the status information you want
2066 - * the key to the array is <module-prefix>.<name>
2067 - * and the values are counters
2070 - * fastcgi.backends = 10
2071 - * fastcgi.active-backends = 6
2072 - * fastcgi.backend.<key>.load = 24
2073 - * fastcgi.backend.<key>....
2075 - * fastcgi.backend.<key>.disconnects = ...
2079 fdevent_handler_t event_handler;
2081 - int (* network_backend_write)(struct server *srv, connection *con, int fd, chunkqueue *cq);
2082 - int (* network_backend_read)(struct server *srv, connection *con, int fd, chunkqueue *cq);
2083 + network_status_t (* network_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
2084 + network_status_t (* network_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
2086 - int (* network_ssl_backend_write)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
2087 - int (* network_ssl_backend_read)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
2088 + network_status_t (* network_ssl_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
2089 + network_status_t (* network_ssl_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
2099 --- ../lighttpd-1.4.11/src/bitset.c 2005-08-22 01:54:12.000000000 +0300
2100 +++ lighttpd-1.5.0/src/bitset.c 2006-07-18 13:03:40.000000000 +0300
2107 #define BITSET_BITS \
2108 ( CHAR_BIT * sizeof(size_t) )
2109 --- ../lighttpd-1.4.11/src/buffer.c 2006-01-13 00:00:45.000000000 +0200
2110 +++ lighttpd-1.5.0/src/buffer.c 2006-07-18 13:03:40.000000000 +0300
2121 buffer* buffer_init(void) {
2125 b = malloc(sizeof(*b));
2147 void buffer_free(buffer *b) {
2150 void buffer_reset(buffer *b) {
2154 /* limit don't reuse buffer larger than ... bytes */
2155 if (b->size > BUFFER_MAX_REUSE_SIZE) {
2168 - * allocate (if neccessary) enough space for 'size' bytes and
2170 + * allocate (if necessary) enough space for 'size' bytes and
2171 * set the 'used' counter to 0
2176 #define BUFFER_PIECE_SIZE 64
2178 int buffer_prepare_copy(buffer *b, size_t size) {
2181 - if ((0 == b->size) ||
2183 + if ((0 == b->size) ||
2185 if (b->size) free(b->ptr);
2190 - /* always allocate a multiply of BUFFER_PIECE_SIZE */
2192 + /* always allocate a multiple of BUFFER_PIECE_SIZE */
2193 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2196 b->ptr = malloc(b->size);
2204 - * increase the internal buffer (if neccessary) to append another 'size' byte
2206 + * increase the internal buffer (if necessary) to append another 'size' byte
2207 * ->used isn't changed
2212 int buffer_prepare_append(buffer *b, size_t size) {
2219 - /* always allocate a multiply of BUFFER_PIECE_SIZE */
2221 + /* always allocate a multiple of BUFFER_PIECE_SIZE */
2222 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2225 b->ptr = malloc(b->size);
2228 } else if (b->used + size > b->size) {
2231 - /* always allocate a multiply of BUFFER_PIECE_SIZE */
2233 + /* always allocate a multiple of BUFFER_PIECE_SIZE */
2234 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2237 b->ptr = realloc(b->ptr, b->size);
2242 int buffer_copy_string(buffer *b, const char *s) {
2246 if (!s || !b) return -1;
2248 s_len = strlen(s) + 1;
2249 @@ -136,26 +136,26 @@
2251 int buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
2252 if (!s || !b) return -1;
2254 - /* removed optimization as we have to keep the empty string
2256 + /* removed optimization as we have to keep the empty string
2257 * in some cases for the config handling
2260 * url.access-deny = ( "" )
2262 if (s_len == 0) return 0;
2265 buffer_prepare_copy(b, s_len + 1);
2268 memcpy(b->ptr, s, s_len);
2269 b->ptr[s_len] = '\0';
2270 b->used = s_len + 1;
2276 int buffer_copy_string_buffer(buffer *b, const buffer *src) {
2277 if (!src) return -1;
2280 if (src->used == 0) {
2283 @@ -201,10 +201,10 @@
2286 * append a string to the end of the buffer
2288 - * the resulting buffer is terminated with a '\0'
2289 - * s is treated as a un-terminated string (a \0 is handled a normal character)
2292 + * the resulting buffer is terminated with a '\0'
2293 + * s is treated as an un-terminated string (a \0 is handled as a normal character)
2296 * @param s the string
2297 * @param s_len size of the string (without the terminating \0)
2299 int buffer_append_string_buffer(buffer *b, const buffer *src) {
2300 if (!src) return -1;
2301 if (src->used == 0) return 0;
2304 return buffer_append_string_len(b, src->ptr, src->used - 1);
2309 int buffer_copy_memory(buffer *b, const char *s, size_t s_len) {
2310 if (!s || !b) return -1;
2316 return buffer_append_memory(b, s, s_len);
2319 @@ -402,46 +402,115 @@
2325 + * init the ptr buffer
2328 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer)
2330 + buffer_ptr *l = calloc(1, sizeof(buffer_ptr));
2337 + * free the buffer_array
2340 +void buffer_ptr_free(buffer_ptr *l)
2343 + buffer_ptr_clear(l);
2348 +void buffer_ptr_clear(buffer_ptr *l)
2350 + assert(NULL != l);
2352 + if (l->free && l->used) {
2354 + for (i = 0; i < l->used; i ++) {
2355 + l->free(l->ptr[i]);
2367 +void buffer_ptr_append(buffer_ptr* l, void *item)
2369 + assert(NULL != l);
2370 + if (l->ptr == NULL) {
2372 + l->ptr = (void **)malloc(sizeof(void *) * l->size);
2374 + else if (l->used == l->size) {
2376 + l->ptr = realloc(l->ptr, sizeof(void *) * l->size);
2378 + l->ptr[l->used++] = item;
2381 +void *buffer_ptr_pop(buffer_ptr* l)
2383 + assert(NULL != l && l->used > 0);
2384 + return l->ptr[--l->used];
2387 +void *buffer_ptr_top(buffer_ptr* l)
2389 + assert(NULL != l && l->used > 0);
2390 + return l->ptr[l->used-1];
2398 buffer_array* buffer_array_init(void) {
2402 b = malloc(sizeof(*b));
2414 void buffer_array_reset(buffer_array *b) {
2421 /* if they are too large, reduce them */
2422 for (i = 0; i < b->used; i++) {
2423 buffer_reset(b->ptr[i]);
2432 - * free the buffer_array
2434 + * free the buffer_array
2438 void buffer_array_free(buffer_array *b) {
2443 for (i = 0; i < b->size; i++) {
2444 if (b->ptr[i]) buffer_free(b->ptr[i]);
2448 buffer *buffer_array_append_get_buffer(buffer_array *b) {
2454 b->ptr = malloc(sizeof(*b->ptr) * b->size);
2455 @@ -467,13 +536,13 @@
2461 if (b->ptr[b->used] == NULL) {
2462 b->ptr[b->used] = buffer_init();
2466 b->ptr[b->used]->used = 0;
2469 return b->ptr[b->used++];
2472 @@ -482,23 +551,23 @@
2474 if (len == 0) return NULL;
2475 if (needle == NULL) return NULL;
2478 if (b->used < len) return NULL;
2481 for(i = 0; i < b->used - len; i++) {
2482 if (0 == memcmp(b->ptr + i, needle, len)) {
2491 buffer *buffer_init_string(const char *str) {
2492 buffer *b = buffer_init();
2495 buffer_copy_string(b, str);
2505 - * check if two buffer contain the same data
2507 + * check if two buffers contain the same data
2509 * HISTORY: this function was pretty much optimized, but didn't handled
2510 * alignment properly.
2512 @@ -517,105 +586,105 @@
2513 if (a->used != b->used) return 0;
2514 if (a->used == 0) return 1;
2516 - return (0 == strcmp(a->ptr, b->ptr));
2517 + return (0 == strncmp(a->ptr, b->ptr, a->used - 1));
2520 int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {
2528 return buffer_is_equal(a, &b);
2531 /* simple-assumption:
2533 - * most parts are equal and doing a case conversion needs time
2536 + * most parts are equal and doing a case conversion takes time
2539 int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len) {
2540 size_t ndx = 0, max_ndx;
2542 size_t mask = sizeof(*al) - 1;
2548 - /* is the alignment correct ? */
2550 + /* is the alignment correct? */
2551 if ( ((size_t)al & mask) == 0 &&
2552 ((size_t)bl & mask) == 0 ) {
2555 max_ndx = ((a_len < b_len) ? a_len : b_len) & ~mask;
2558 for (; ndx < max_ndx; ndx += sizeof(*al)) {
2559 if (*al != *bl) break;
2573 max_ndx = ((a_len < b_len) ? a_len : b_len);
2576 for (; ndx < max_ndx; ndx++) {
2577 char a1 = *a++, b1 = *b++;
2581 if ((a1 >= 'A' && a1 <= 'Z') && (b1 >= 'a' && b1 <= 'z'))
2583 else if ((a1 >= 'a' && a1 <= 'z') && (b1 >= 'A' && b1 <= 'Z'))
2585 if ((a1 - b1) != 0) return (a1 - b1);
2597 * check if the rightmost bytes of the string are equal.
2604 int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
2605 /* no, len -> equal */
2606 if (len == 0) return 1;
2609 /* len > 0, but empty buffers -> not equal */
2610 if (b1->used == 0 || b2->used == 0) return 0;
2613 /* buffers too small -> not equal */
2614 - if (b1->used - 1 < len || b1->used - 1 < len) return 0;
2616 - if (0 == strncmp(b1->ptr + b1->used - 1 - len,
2617 + if (b1->used - 1 < len || b2->used - 1 < len) return 0;
2619 + if (0 == strncmp(b1->ptr + b1->used - 1 - len,
2620 b2->ptr + b2->used - 1 - len, len)) {
2628 int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
2633 if (in_len * 2 < in_len) return -1;
2636 buffer_prepare_copy(b, in_len * 2 + 1);
2639 for (i = 0; i < in_len; i++) {
2640 b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F];
2641 b->ptr[b->used++] = hex_chars[in[i] & 0x0F];
2643 b->ptr[b->used++] = '\0';
2650 0 1 2 3 4 5 6 7 8 9 A B C D E F
2652 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2653 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2654 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2655 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, /* 20 - 2F space " # $ % & ' + , / */
2656 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 30 - 3F : ; = ? @ < > */
2657 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
2659 0 1 2 3 4 5 6 7 8 9 A B C D E F
2661 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2662 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2663 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2664 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, /* 20 - 2F space " # $ % & ' + , / */
2665 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 30 - 3F : ; = ? @ < > */
2666 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
2668 0 1 2 3 4 5 6 7 8 9 A B C D E F
2670 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2671 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2672 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2673 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F & */
2674 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 30 - 3F < > */
2675 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
2677 0 1 2 3 4 5 6 7 8 9 A B C D E F
2679 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2680 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2681 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2682 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F & */
2683 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 30 - 3F < > */
2684 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
2685 @@ -712,12 +781,12 @@
2686 0 1 2 3 4 5 6 7 8 9 A B C D E F
2688 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2689 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2690 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
2691 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
2692 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
2693 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
2694 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
2695 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2696 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
2697 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
2698 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
2699 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
2700 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
2701 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 70 - 7F */
2702 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 - 8F */
2703 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 - 9F */
2704 @@ -734,13 +803,12 @@
2705 unsigned char *ds, *d;
2707 const char *map = NULL;
2710 if (!s || !b) return -1;
2712 - if (b->ptr[b->used - 1] != '\0') {
2716 + if (b->used == 0) return -1;
2718 + if (b->ptr[b->used - 1] != '\0') return -1;
2720 if (s_len == 0) return 0;
2723 @@ -760,12 +828,12 @@
2724 map = encoded_chars_hex;
2726 case ENCODING_UNSET:
2728 + return buffer_append_string_len(b, s, s_len);
2731 assert(map != NULL);
2733 - /* count to-be-encoded-characters */
2735 + /* count to-be-encoded characters */
2736 for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2745 buffer_prepare_append(b, d_len);
2748 for (ds = (unsigned char *)s, d = (unsigned char *)b->ptr + b->used - 1, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2751 @@ -820,16 +888,16 @@
2755 - /* terminate buffer and calculate new length */
2756 + /* terminate buffer and calculate new length */
2757 b->ptr[b->used + d_len - 1] = '\0';
2766 -/* decodes url-special-chars inplace.
2767 +/* decodes url-special chars in-place.
2768 * replaces non-printable characters with '_'
2771 @@ -854,10 +922,10 @@
2772 low = hex2int(*(src + 2));
2774 high = (high << 4) | low;
2776 - /* map control-characters out */
2778 + /* map out control characters */
2779 if (high < 32 || high == 127) high = '_';
2786 * /abc/./xyz gets /abc/xyz
2787 * /abc//xyz gets /abc/xyz
2789 - * NOTE: src and dest can point to the same buffer, in which case,
2790 + * NOTE: src and dest can point to the same buffer, in which case
2791 * the operation is performed in-place.
2794 @@ -979,7 +1047,7 @@
2796 int light_isxdigit(int c) {
2797 if (light_isdigit(c)) return 1;
2801 return (c >= 'a' && c <= 'f');
2803 @@ -993,31 +1061,56 @@
2804 return light_isdigit(c) || light_isalpha(c);
2807 +#undef BUFFER_CTYPE_FUNC
2808 +#define BUFFER_CTYPE_FUNC(type) \
2809 + int buffer_is##type(buffer *b) { \
2811 + if (b->used < 2) return 0; \
2813 + len = b->used - 1; \
2814 + /* c-string only */ \
2815 + if (b->ptr[len] != '\0') { \
2818 + /* check on the whole string */ \
2819 + for (i = 0; i < len; i ++) { \
2820 + if (!light_is##type(b->ptr[i])) { \
2827 +BUFFER_CTYPE_FUNC(digit)
2828 +BUFFER_CTYPE_FUNC(xdigit)
2829 +BUFFER_CTYPE_FUNC(alpha)
2830 +BUFFER_CTYPE_FUNC(alnum)
2832 int buffer_to_lower(buffer *b) {
2836 if (b->used == 0) return 0;
2839 for (c = b->ptr; *c; c++) {
2840 if (*c >= 'A' && *c <= 'Z') {
2850 int buffer_to_upper(buffer *b) {
2854 if (b->used == 0) return 0;
2857 for (c = b->ptr; *c; c++) {
2858 if (*c >= 'a' && *c <= 'z') {
2866 --- ../lighttpd-1.4.11/src/buffer.h 2006-01-13 00:00:45.000000000 +0200
2867 +++ lighttpd-1.5.0/src/buffer.h 2006-07-18 13:03:40.000000000 +0300
2878 +typedef void (*buffer_ptr_free_t)(void *p);
2884 + buffer_ptr_free_t free;
2898 - size_t offset; /* input-pointer */
2900 - size_t used; /* output-pointer */
2902 + size_t offset; /* input pointer */
2904 + size_t used; /* output pointer */
2908 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer);
2909 +void buffer_ptr_free(buffer_ptr *b);
2910 +void buffer_ptr_clear(buffer_ptr *b);
2911 +void buffer_ptr_append(buffer_ptr *b, void *item);
2912 +void *buffer_ptr_pop(buffer_ptr *b);
2913 +void *buffer_ptr_top(buffer_ptr *b);
2915 buffer_array* buffer_array_init(void);
2916 void buffer_array_free(buffer_array *b);
2917 void buffer_array_reset(buffer_array *b);
2919 buffer* buffer_init_string(const char *str);
2920 void buffer_free(buffer *b);
2921 void buffer_reset(buffer *b);
2924 int buffer_prepare_copy(buffer *b, size_t size);
2925 int buffer_prepare_append(buffer *b, size_t size);
2931 - ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of a href */
2932 - ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus coding / too as %2F */
2933 - ENCODING_HTML, /* & becomes & and so on */
2934 + ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of an href */
2935 + ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus encoding "/" as "%2F" */
2936 + ENCODING_HTML, /* "&" becomes "&" and so on */
2937 ENCODING_MINIMAL_XML, /* minimal encoding for xml */
2938 ENCODING_HEX /* encode string as hex */
2939 } buffer_encoding_t;
2940 @@ -111,20 +127,23 @@
2941 int light_isalpha(int c);
2942 int light_isalnum(int c);
2944 +#define BUFFER_CTYPE_FUNC(type) int buffer_is##type(buffer *b);
2945 +BUFFER_CTYPE_FUNC(digit)
2946 +BUFFER_CTYPE_FUNC(xdigit)
2947 +BUFFER_CTYPE_FUNC(alpha)
2948 +BUFFER_CTYPE_FUNC(alnum)
2950 +#define BUF_STR(x) x->ptr
2951 #define BUFFER_APPEND_STRING_CONST(x, y) \
2952 buffer_append_string_len(x, y, sizeof(y) - 1)
2954 #define BUFFER_COPY_STRING_CONST(x, y) \
2955 buffer_copy_string_len(x, y, sizeof(y) - 1)
2957 -#define BUFFER_APPEND_SLASH(x) \
2958 - if (x->used > 1 && x->ptr[x->used - 2] != '/') { BUFFER_APPEND_STRING_CONST(x, "/"); }
2960 #define CONST_STR_LEN(x) x, x ? sizeof(x) - 1 : 0
2961 -#define CONST_BUF_LEN(x) x->ptr, x->used ? x->used - 1 : 0
2962 +#define CONST_BUF_LEN(x) BUF_STR(x), x->used ? x->used - 1 : 0
2965 -#define SEGFAULT() do { fprintf(stderr, "%s.%d: aborted\n", __FILE__, __LINE__); abort(); } while(0)
2967 #define UNUSED(x) ( (void)(x) )
2970 --- ../lighttpd-1.4.11/src/chunk.c 2005-11-18 15:18:19.000000000 +0200
2971 +++ lighttpd-1.5.0/src/chunk.c 2006-09-07 00:57:05.000000000 +0300
2974 * the network chunk-API
2981 #include <sys/types.h>
2982 #include <sys/stat.h>
2983 -#include <sys/mman.h>
2987 -#include <unistd.h>
2995 +#include "sys-mmap.h"
2996 +#include "sys-files.h"
2998 chunkqueue *chunkqueue_init(void) {
3002 cq = calloc(1, sizeof(*cq));
3015 static chunk *chunk_init(void) {
3019 c = calloc(1, sizeof(*c));
3022 c->mem = buffer_init();
3023 c->file.name = buffer_init();
3025 c->file.mmap.start = MAP_FAILED;
3032 static void chunk_free(chunk *c) {
3036 buffer_free(c->mem);
3037 buffer_free(c->file.name);
3041 static void chunk_reset(chunk *c) {
3045 buffer_reset(c->mem);
3047 if (c->file.is_temp && !buffer_is_empty(c->file.name)) {
3048 unlink(c->file.name->ptr);
3052 buffer_reset(c->file.name);
3054 if (c->file.fd != -1) {
3057 void chunkqueue_free(chunkqueue *cq) {
3064 for (c = cq->first; c; ) {
3071 for (c = cq->unused; c; ) {
3081 static chunk *chunkqueue_get_unused_chunk(chunkqueue *cq) {
3084 - /* check if we have a unused chunk */
3086 + /* check if we have an unused chunk */
3090 @@ -109,18 +110,18 @@
3092 cq->unused_chunks--;
3099 static int chunkqueue_prepend_chunk(chunkqueue *cq, chunk *c) {
3100 c->next = cq->first;
3104 if (cq->last == NULL) {
3112 @@ -129,19 +130,19 @@
3118 if (cq->first == NULL) {
3126 void chunkqueue_reset(chunkqueue *cq) {
3128 /* move everything to the unused queue */
3130 - /* mark all read written */
3132 + /* mark all read written */
3133 for (c = cq->first; c; c = c->next) {
3138 c->offset = c->file.length;
3145 @@ -158,97 +159,98 @@
3146 chunkqueue_remove_finished_chunks(cq);
3149 + cq->is_closed = 0;
3152 int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
3156 if (len == 0) return 0;
3159 c = chunkqueue_get_unused_chunk(cq);
3162 c->type = FILE_CHUNK;
3165 buffer_copy_string_buffer(c->file.name, fn);
3166 c->file.start = offset;
3167 c->file.length = len;
3171 chunkqueue_append_chunk(cq, c);
3177 int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
3181 if (mem->used == 0) return 0;
3184 c = chunkqueue_get_unused_chunk(cq);
3185 c->type = MEM_CHUNK;
3187 buffer_copy_string_buffer(c->mem, mem);
3190 chunkqueue_append_chunk(cq, c);
3196 int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
3200 if (mem->used == 0) return 0;
3203 c = chunkqueue_get_unused_chunk(cq);
3204 c->type = MEM_CHUNK;
3206 buffer_copy_string_buffer(c->mem, mem);
3209 chunkqueue_prepend_chunk(cq, c);
3215 int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
3219 if (len == 0) return 0;
3222 c = chunkqueue_get_unused_chunk(cq);
3223 c->type = MEM_CHUNK;
3225 buffer_copy_string_len(c->mem, mem, len - 1);
3228 chunkqueue_append_chunk(cq, c);
3234 buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
3238 c = chunkqueue_get_unused_chunk(cq);
3241 c->type = MEM_CHUNK;
3243 buffer_reset(c->mem);
3246 chunkqueue_prepend_chunk(cq, c);
3252 buffer *chunkqueue_get_append_buffer(chunkqueue *cq) {
3256 c = chunkqueue_get_unused_chunk(cq);
3259 c->type = MEM_CHUNK;
3261 buffer_reset(c->mem);
3264 chunkqueue_append_chunk(cq, c);
3271 chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
3273 buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX");
3276 c = chunkqueue_get_unused_chunk(cq);
3278 c->type = FILE_CHUNK;
3279 @@ -273,12 +275,12 @@
3282 /* we have several tempdirs, only if all of them fail we jump out */
3285 for (i = 0; i < cq->tempdirs->used; i++) {
3286 data_string *ds = (data_string *)cq->tempdirs->data[i];
3288 buffer_copy_string_buffer(template, ds->value);
3289 - BUFFER_APPEND_SLASH(template);
3290 + PATHNAME_APPEND_SLASH(template);
3291 BUFFER_APPEND_STRING_CONST(template, "lighttpd-upload-XXXXXX");
3293 if (-1 != (c->file.fd = mkstemp(template->ptr))) {
3295 chunkqueue_append_chunk(cq, c);
3297 buffer_free(template);
3304 off_t chunkqueue_length(chunkqueue *cq) {
3309 for (c = cq->first; c; c = c->next) {
3312 @@ -321,14 +323,14 @@
3321 off_t chunkqueue_written(chunkqueue *cq) {
3326 for (c = cq->first; c; c = c->next) {
3338 @@ -355,12 +357,13 @@
3342 + if (c->mem->used == 0) is_finished = 1;
3343 if (c->offset == (off_t)c->mem->used - 1) is_finished = 1;
3346 - if (c->offset == c->file.length) is_finished = 1;
3347 + if (c->offset == c->file.length) is_finished = 1;
3354 @@ -383,3 +386,50 @@
3359 +void chunkqueue_print(chunkqueue *cq) {
3362 + for (c = cq->first; c; c = c->next) {
3363 + fprintf(stderr, "(mem) %s", c->mem->ptr + c->offset);
3365 + fprintf(stderr, "\r\n");
3370 + * remove the last chunk if it is empty
3373 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq) {
3375 + if (!cq->last) return;
3376 + if (!cq->first) return;
3378 + if (cq->first == cq->last) {
3381 + if (c->type != MEM_CHUNK) return;
3382 + if (c->mem->used == 0) {
3384 + cq->first = cq->last = NULL;
3389 + for (c = cq->first; c->next; c = c->next) {
3390 + if (c->type != MEM_CHUNK) continue;
3391 + if (c->mem->used != 0) continue;
3393 + if (c->next == cq->last) {
3396 + chunk_free(c->next);
3405 --- ../lighttpd-1.4.11/src/chunk.h 2005-11-01 09:32:21.000000000 +0200
3406 +++ lighttpd-1.5.0/src/chunk.h 2006-09-07 00:57:05.000000000 +0300
3409 typedef struct chunk {
3410 enum { UNUSED_CHUNK, MEM_CHUNK, FILE_CHUNK } type;
3413 buffer *mem; /* either the storage of the mem-chunk or the read-ahead buffer */
3417 off_t length; /* octets to send from the starting offset */
3422 char *start; /* the start pointer of the mmap'ed area */
3423 size_t length; /* size of the mmap'ed area */
3424 - off_t offset; /* start is <n> octet away from the start of the file */
3425 + off_t offset; /* start is <n> octets away from the start of the file */
3428 - int is_temp; /* file is temporary and will be deleted if on cleanup */
3429 + int is_temp; /* file is temporary and will be deleted on cleanup */
3432 - off_t offset; /* octets sent from this chunk
3433 - the size of the chunk is either
3435 + off_t offset; /* octets sent from this chunk
3436 + the size of the chunk is either
3437 - mem-chunk: mem->used - 1
3438 - file-chunk: file.length
3451 size_t unused_chunks;
3455 + int is_closed; /* the input to this CQ is closed */
3457 off_t bytes_in, bytes_out;
3461 buffer * chunkqueue_get_append_buffer(chunkqueue *c);
3462 buffer * chunkqueue_get_prepend_buffer(chunkqueue *c);
3463 chunk * chunkqueue_get_append_tempfile(chunkqueue *cq);
3464 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq);
3466 int chunkqueue_remove_finished_chunks(chunkqueue *cq);
3470 int chunkqueue_is_empty(chunkqueue *c);
3472 +void chunkqueue_print(chunkqueue *cq);
3475 --- ../lighttpd-1.4.11/src/configfile-glue.c 2006-03-03 20:14:56.000000000 +0200
3476 +++ lighttpd-1.5.0/src/configfile-glue.c 2006-09-07 00:57:05.000000000 +0300
3484 * are the external interface of lighttpd. The functions
3485 * are used by the server itself and the plugins.
3487 - * The main-goal is to have a small library in the end
3488 - * which is linked against both and which will define
3489 + * The main-goal is to have a small library in the end
3490 + * which is linked against both and which will define
3491 * the interface itself in the end.
3498 int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[]) {
3503 for (i = 0; cv[i].key; i++) {
3506 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3514 switch (cv[i].type) {
3515 case T_CONFIG_ARRAY:
3516 if (du->type == TYPE_ARRAY) {
3518 data_array *da = (data_array *)du;
3521 for (j = 0; j < da->value->used; j++) {
3522 if (da->value->data[j]->type == TYPE_STRING) {
3523 data_string *ds = data_string_init();
3526 buffer_copy_string_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
3527 if (!da->is_index_key) {
3528 /* the id's were generated automaticly, as we copy now we might have to renumber them
3529 - * this is used to prepend server.modules by mod_indexfiles as it has to be loaded
3530 + * this is used to prepend server.modules by mod_indexfiles as it has to be loaded
3531 * before mod_fastcgi and friends */
3532 buffer_copy_string_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
3536 array_insert_unique(cv[i].destination, (data_unset *)ds);
3538 - log_error_write(srv, __FILE__, __LINE__, "sssd",
3539 - "the key of and array can only be a string or a integer, variable:",
3540 - cv[i].key, "type:", da->value->data[j]->type);
3542 + log_error_write(srv, __FILE__, __LINE__, "sssd",
3543 + "the key of and array can only be a string or a integer, variable:",
3544 + cv[i].key, "type:", da->value->data[j]->type);
3550 log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", cv[i].key, "array of strings");
3556 case T_CONFIG_STRING:
3557 if (du->type == TYPE_STRING) {
3558 data_string *ds = (data_string *)du;
3561 buffer_copy_string_buffer(cv[i].destination, ds->value);
3562 + } else if (du->type == TYPE_INTEGER) {
3563 + data_integer *di = (data_integer *)du;
3565 + buffer_copy_long(cv[i].destination, di->value);
3567 log_error_write(srv, __FILE__, __LINE__, "ssss", "unexpected type for key: ", cv[i].key, "(string)", "\"...\"");
3575 case TYPE_INTEGER: {
3576 data_integer *di = (data_integer *)du;
3579 *((unsigned short *)(cv[i].destination)) = di->value;
3583 data_string *ds = (data_string *)du;
3586 + if (buffer_isdigit(ds->value)) {
3587 + *((unsigned short *)(cv[i].destination)) = strtol(ds->value->ptr, NULL, 10);
3591 log_error_write(srv, __FILE__, __LINE__, "ssb", "get a string but expected a short:", cv[i].key, ds->value);
3597 @@ -100,30 +110,36 @@
3598 case T_CONFIG_BOOLEAN:
3599 if (du->type == TYPE_STRING) {
3600 data_string *ds = (data_string *)du;
3603 if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
3604 *((unsigned short *)(cv[i].destination)) = 1;
3605 } else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
3606 *((unsigned short *)(cv[i].destination)) = 0;
3608 log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
3614 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
3620 case T_CONFIG_LOCAL:
3621 case T_CONFIG_UNSET:
3623 + case T_CONFIG_UNSUPPORTED:
3624 + log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found unsupported key:", cv[i].key, "-", (char *)(cv[i].destination));
3626 + srv->config_unsupported = 1;
3629 case T_CONFIG_DEPRECATED:
3630 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
3633 srv->config_deprecated = 1;
3639 @@ -133,25 +149,25 @@
3640 int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
3645 for (i = 0; cv[i].key; i++) {
3646 data_string *touched;
3649 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3658 touched = data_string_init();
3661 buffer_copy_string(touched->value, "");
3662 buffer_copy_string_buffer(touched->key, du->key);
3665 array_insert_unique(srv->config_touched, (data_unset *)touched);
3669 return config_insert_values_internal(srv, ca, cv);
3672 @@ -191,25 +207,25 @@
3675 /* pass the rules */
3679 case COMP_HTTP_HOST: {
3680 char *ck_colon = NULL, *val_colon = NULL;
3683 if (!buffer_is_empty(con->uri.authority)) {
3688 * append server-port to the HTTP_POST if necessary
3692 l = con->uri.authority;
3696 case CONFIG_COND_NE:
3697 case CONFIG_COND_EQ:
3698 ck_colon = strchr(dc->string->ptr, ':');
3699 val_colon = strchr(l->ptr, ':');
3702 if (ck_colon == val_colon) {
3703 /* nothing to do with it */
3705 @@ -230,21 +246,21 @@
3710 + l = srv->empty_string;
3714 case COMP_HTTP_REMOTEIP: {
3716 - /* handle remoteip limitations
3718 + /* handle remoteip limitations
3720 * "10.0.0.1" is provided for all comparisions
3723 * only for == and != we support
3730 if ((dc->cond == CONFIG_COND_EQ ||
3731 dc->cond == CONFIG_COND_NE) &&
3732 (con->dst_addr.plain.sa_family == AF_INET) &&
3733 @@ -253,41 +269,48 @@
3736 struct in_addr val_inp;
3739 + if (con->conf.log_condition_handling) {
3740 + l = srv->empty_string;
3742 + log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key,
3743 + "(", l, ") compare to", dc->string);
3746 if (*(nm_slash+1) == '\0') {
3747 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string);
3750 return COND_RESULT_FALSE;
3754 nm_bits = strtol(nm_slash + 1, &err, 10);
3758 log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, *err);
3761 return COND_RESULT_FALSE;
3765 /* take IP convert to the native */
3766 buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr);
3769 if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) {
3770 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3773 return COND_RESULT_FALSE;
3777 if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) {
3778 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3781 return COND_RESULT_FALSE;
3787 nm = htonl(~((1 << (32 - nm_bits)) - 1));
3790 if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) {
3791 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
3793 @@ -302,13 +325,17 @@
3797 + case COMP_HTTP_QUERYSTRING:
3798 + l = con->uri.query;
3801 case COMP_SERVER_SOCKET:
3802 l = srv_sock->srv_token;
3805 case COMP_HTTP_REFERER: {
3809 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
3814 return COND_RESULT_FALSE;
3819 if (con->conf.log_condition_handling) {
3820 log_error_write(srv, __FILE__, __LINE__, "bsbs", dc->comp_key,
3821 @@ -346,10 +373,10 @@
3823 return COND_RESULT_FALSE;
3827 if (con->conf.log_condition_handling) {
3828 log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key,
3829 - "(", l, ") compare to ", dc->string);
3830 + "(", l, ") compare to", dc->string);
3833 case CONFIG_COND_NE:
3834 @@ -365,13 +392,13 @@
3835 case CONFIG_COND_MATCH: {
3836 cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
3841 #define elementsof(x) (sizeof(x) / sizeof(x[0]))
3843 n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0,
3844 cache->matches, elementsof(cache->matches));
3847 cache->patterncount = n;
3849 cache->comp_value = l;
3856 return COND_RESULT_FALSE;
3860 cond_cache_t *caches = con->cond_cache;
3862 if (COND_RESULT_UNSET == caches[dc->context_ndx].result) {
3863 + if (con->conf.log_condition_handling) {
3864 + log_error_write(srv, __FILE__, __LINE__, "sds", "=== start of", dc->context_ndx, "condition block ===");
3866 if (COND_RESULT_TRUE == (caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc))) {
3869 @@ -409,11 +439,11 @@
3871 if (con->conf.log_condition_handling) {
3872 log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3873 - "(uncached) result:",
3875 caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3878 - if (con->conf.log_condition_handling) {
3879 + if (con->conf.log_condition_cache_handling) {
3880 log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3882 caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3883 @@ -422,10 +452,20 @@
3884 return caches[dc->context_ndx].result;
3887 -int config_check_cond(server *srv, connection *con, data_config *dc) {
3888 - if (con->conf.log_condition_handling) {
3889 - log_error_write(srv, __FILE__, __LINE__, "s", "=== start of condition block ===");
3890 +void config_cond_cache_reset(server *srv, connection *con) {
3891 +#if COND_RESULT_UNSET
3894 + for (i = srv->config_context->used - 1; i >= 0; i --) {
3895 + con->cond_cache[i].result = COND_RESULT_UNSET;
3896 + con->cond_cache[i].patterncount = 0;
3899 + memset(con->cond_cache, 0, sizeof(cond_cache_t) * srv->config_context->used);
3903 +int config_check_cond(server *srv, connection *con, data_config *dc) {
3904 return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
3907 @@ -443,3 +483,85 @@
3911 +/* return <0 on error
3912 + * return 0-x if matched (and replaced)
3914 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result)
3918 + pcre_extra *extra;
3919 + const char *pattern;
3920 + size_t pattern_len;
3923 + pcre_keyvalue *kv;
3927 + for (i = 0; i < kvb->used; i++) {
3931 + extra = kv->key_extra;
3932 + pattern = kv->value->ptr;
3933 + pattern_len = kv->value->used - 1;
3935 + if ((n = pcre_exec(match, extra, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
3936 + if (n != PCRE_ERROR_NOMATCH) {
3940 + const char **list;
3941 + size_t start, end;
3945 + pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
3947 + /* search for $[0-9] */
3949 + buffer_reset(result);
3951 + start = 0; end = pattern_len;
3952 + for (k = 0; k < pattern_len; k++) {
3953 + if ((pattern[k] == '$' || pattern[k] == '%') &&
3954 + isdigit((unsigned char)pattern[k + 1])) {
3957 + size_t num = pattern[k + 1] - '0';
3961 + buffer_append_string_len(result, pattern + start, end - start);
3963 + if (pattern[k] == '$') {
3964 + /* n is always > 0 */
3965 + if (num < (size_t)n) {
3966 + buffer_append_string(result, list[num]);
3969 + config_append_cond_match_buffer(con, context, result, num);
3977 + buffer_append_string_len(result, pattern + start, pattern_len - start);
3985 + return PCRE_ERROR_NOMATCH;
3993 --- ../lighttpd-1.4.11/src/configfile.c 2006-02-15 14:26:42.000000000 +0200
3994 +++ lighttpd-1.5.0/src/configfile.c 2006-09-07 00:57:05.000000000 +0300
3999 -#include <unistd.h>
4008 -#include "license.h"
4011 #include "configparser.h"
4012 #include "configfile.h"
4013 #include "proc_open.h"
4015 +#include "sys-files.h"
4016 +#include "sys-process.h"
4020 +#define PATH_MAX 64
4023 static int config_insert(server *srv) {
4026 buffer *stat_cache_string;
4028 - config_values_t cv[] = {
4030 + config_values_t cv[] = {
4031 { "server.bind", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 0 */
4032 { "server.errorlog", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 1 */
4033 { "server.errorfile-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 2 */
4035 { "server.tag", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
4036 { "server.use-ipv6", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
4037 { "server.modules", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER }, /* 9 */
4040 { "server.event-handler", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 10 */
4041 { "server.pid-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 11 */
4042 { "server.max-request-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
4044 { "server.max-keep-alive-requests", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
4045 { "server.name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 18 */
4046 { "server.max-keep-alive-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 19 */
4049 { "server.max-read-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 20 */
4050 { "server.max-write-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 21 */
4051 { "server.error-handler-404", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 22 */
4052 { "server.max-fds", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 23 */
4054 { "server.follow-symlink", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 24 */
4056 + { "server.follow-symlink",
4057 + "Your system lacks lstat(). We cant differ symlinks from files."
4058 + "Please remove server.follow-symlinks from your config.",
4059 + T_CONFIG_UNSUPPORTED, T_CONFIG_SCOPE_UNSET }, /* 24 */
4061 { "server.kbytes-per-second", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 25 */
4062 { "connection.kbytes-per-second", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 26 */
4063 { "mimetype.use-xattr", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 27 */
4064 { "mimetype.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 28 */
4065 { "ssl.pemfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 29 */
4068 { "ssl.engine", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 30 */
4071 { "debug.log-file-not-found", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 31 */
4072 { "debug.log-request-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 32 */
4073 { "debug.log-response-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 33 */
4074 { "debug.log-request-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 34 */
4077 { "server.protocol-http11", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 35 */
4078 { "debug.log-request-header-on-error", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 36 */
4079 { "debug.log-state-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 37 */
4080 { "ssl.ca-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 38 */
4083 { "server.errorlog-use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 39 */
4084 { "server.range-requests", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 40 */
4085 { "server.stat-cache-engine", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 41 */
4087 { "server.network-backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 43 */
4088 { "server.upload-dirs", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 44 */
4089 { "server.core-files", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 45 */
4091 + { "debug.log-condition-cache-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 46 */
4093 { "server.host", "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
4094 { "server.docroot", "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
4095 { "server.virtual-root", "load mod_simple_vhost and use simple-vhost.server-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
4096 @@ -90,11 +100,11 @@
4097 { "server.groupid", "use server.groupname instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
4098 { "server.use-keep-alive", "use server.max-keep-alive-requests = 0 instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
4099 { "server.force-lower-case-files", "use server.force-lowercase-filenames instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
4102 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
4108 cv[0].destination = srv->srvconf.bindhost;
4109 cv[1].destination = srv->srvconf.errorlog_file;
4110 @@ -102,33 +112,33 @@
4111 cv[4].destination = srv->srvconf.username;
4112 cv[5].destination = srv->srvconf.groupname;
4113 cv[6].destination = &(srv->srvconf.port);
4116 cv[9].destination = srv->srvconf.modules;
4117 cv[10].destination = srv->srvconf.event_handler;
4118 cv[11].destination = srv->srvconf.pid_file;
4121 cv[13].destination = &(srv->srvconf.max_worker);
4122 cv[23].destination = &(srv->srvconf.max_fds);
4123 cv[36].destination = &(srv->srvconf.log_request_header_on_error);
4124 cv[37].destination = &(srv->srvconf.log_state_handling);
4127 cv[39].destination = &(srv->srvconf.errorlog_use_syslog);
4130 stat_cache_string = buffer_init();
4131 cv[41].destination = stat_cache_string;
4132 cv[43].destination = srv->srvconf.network_backend;
4133 cv[44].destination = srv->srvconf.upload_tempdirs;
4134 cv[45].destination = &(srv->srvconf.enable_cores);
4137 cv[42].destination = &(srv->srvconf.max_conns);
4138 cv[12].destination = &(srv->srvconf.max_request_size);
4139 srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
4141 assert(srv->config_storage);
4144 for (i = 0; i < srv->config_context->used; i++) {
4148 s = calloc(1, sizeof(specific_config));
4150 s->document_root = buffer_init();
4156 s->follow_symlink = 1;
4158 s->kbytes_per_second = 0;
4159 s->allow_http11 = 1;
4160 s->range_requests = 1;
4161 @@ -154,24 +166,27 @@
4162 s->global_kbytes_per_second = 0;
4163 s->global_bytes_per_second_cnt = 0;
4164 s->global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
4167 cv[2].destination = s->errorfile_prefix;
4170 cv[7].destination = s->server_tag;
4171 cv[8].destination = &(s->use_ipv6);
4177 cv[14].destination = s->document_root;
4178 cv[15].destination = &(s->force_lowercase_filenames);
4179 cv[16].destination = &(s->log_condition_handling);
4180 + cv[46].destination = &(s->log_condition_cache_handling);
4181 cv[17].destination = &(s->max_keep_alive_requests);
4182 cv[18].destination = s->server_name;
4183 cv[19].destination = &(s->max_keep_alive_idle);
4184 cv[20].destination = &(s->max_read_idle);
4185 cv[21].destination = &(s->max_write_idle);
4186 cv[22].destination = s->error_handler;
4188 cv[24].destination = &(s->follow_symlink);
4191 cv[25].destination = &(s->global_kbytes_per_second);
4192 cv[26].destination = &(s->kbytes_per_second);
4193 @@ -179,23 +194,23 @@
4194 cv[28].destination = s->mimetypes;
4195 cv[29].destination = s->ssl_pemfile;
4196 cv[30].destination = &(s->is_ssl);
4199 cv[31].destination = &(s->log_file_not_found);
4200 cv[32].destination = &(s->log_request_handling);
4201 cv[33].destination = &(s->log_response_header);
4202 cv[34].destination = &(s->log_request_header);
4205 cv[35].destination = &(s->allow_http11);
4206 cv[38].destination = s->ssl_ca_file;
4207 cv[40].destination = &(s->range_requests);
4210 srv->config_storage[i] = s;
4213 if (0 != (ret = config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv))) {
4219 if (buffer_is_empty(stat_cache_string)) {
4220 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
4221 } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) {
4222 @@ -205,22 +220,22 @@
4223 } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("disable"))) {
4224 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE;
4226 - log_error_write(srv, __FILE__, __LINE__, "sb",
4227 + log_error_write(srv, __FILE__, __LINE__, "sb",
4228 "server.stat-cache-engine can be one of \"disable\", \"simple\", \"fam\", but not:", stat_cache_string);
4229 ret = HANDLER_ERROR;
4233 buffer_free(stat_cache_string);
4242 -#define PATCH(x) con->conf.x = s->x
4244 + con->conf.x = s->x
4245 int config_setup_connection(server *srv, connection *con) {
4246 specific_config *s = srv->config_storage[0];
4249 PATCH(allow_http11);
4251 PATCH(document_root);
4252 @@ -231,25 +246,28 @@
4254 PATCH(error_handler);
4255 PATCH(errorfile_prefix);
4257 PATCH(follow_symlink);
4260 PATCH(kbytes_per_second);
4261 PATCH(global_kbytes_per_second);
4262 PATCH(global_bytes_per_second_cnt);
4265 con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
4266 buffer_copy_string_buffer(con->server_name, s->server_name);
4269 PATCH(log_request_header);
4270 PATCH(log_response_header);
4271 PATCH(log_request_handling);
4272 PATCH(log_condition_handling);
4273 + PATCH(log_condition_cache_handling);
4274 PATCH(log_file_not_found);
4277 PATCH(range_requests);
4278 PATCH(force_lowercase_filenames);
4285 @@ -257,22 +275,22 @@
4287 int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
4291 /* skip the first, the global context */
4292 for (i = 1; i < srv->config_context->used; i++) {
4293 data_config *dc = (data_config *)srv->config_context->data[i];
4294 specific_config *s = srv->config_storage[i];
4298 if (comp != dc->comp) continue;
4301 /* condition didn't match */
4302 if (!config_check_cond(srv, con, dc)) continue;
4306 for (j = 0; j < dc->value->used; j++) {
4307 data_unset *du = dc->value->data[j];
4310 if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.document-root"))) {
4311 PATCH(document_root);
4312 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.range-requests"))) {
4313 @@ -299,8 +317,10 @@
4315 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.engine"))) {
4318 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.follow-symlink"))) {
4319 PATCH(follow_symlink);
4321 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.name"))) {
4322 buffer_copy_string_buffer(con->server_name, s->server_name);
4323 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.tag"))) {
4324 @@ -315,11 +335,13 @@
4325 PATCH(log_response_header);
4326 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-handling"))) {
4327 PATCH(log_condition_handling);
4328 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-cache-handling"))) {
4329 + PATCH(log_condition_cache_handling);
4330 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-file-not-found"))) {
4331 PATCH(log_file_not_found);
4332 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
4333 PATCH(allow_http11);
4334 - } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
4335 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
4336 PATCH(force_lowercase_filenames);
4337 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
4338 PATCH(global_kbytes_per_second);
4348 @@ -336,15 +358,15 @@
4354 const buffer *source;
4370 if (0 != stream_open(&(t->s), t->file)) {
4371 - log_error_write(srv, __FILE__, __LINE__, "sbss",
4372 + log_error_write(srv, __FILE__, __LINE__, "sbss",
4373 "opening configfile ", t->file, "failed:", strerror(errno));
4374 buffer_free(t->file);
4377 t->size = t->s.size;
4386 static int config_skip_comment(tokenizer_t *t) {
4388 assert(t->input[t->offset] == '#');
4389 - for (i = 1; t->input[t->offset + i] &&
4390 + for (i = 1; t->input[t->offset + i] &&
4391 (t->input[t->offset + i] != '\n' && t->input[t->offset + i] != '\r');
4394 @@ -411,44 +433,44 @@
4395 static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *token) {
4400 for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
4401 char c = t->input[t->offset];
4402 const char *start = NULL;
4409 if (t->input[t->offset + 1] == '>') {
4413 buffer_copy_string(token, "=>");
4416 tid = TK_ARRAY_ASSIGN;
4418 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4419 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4420 "source:", t->source,
4421 - "line:", t->line, "pos:", t->line_pos,
4422 + "line:", t->line, "pos:", t->line_pos,
4423 "use => for assignments in arrays");
4426 } else if (t->in_cond) {
4427 if (t->input[t->offset + 1] == '=') {
4431 buffer_copy_string(token, "==");
4435 } else if (t->input[t->offset + 1] == '~') {
4439 buffer_copy_string(token, "=~");
4444 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4445 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4446 "source:", t->source,
4447 - "line:", t->line, "pos:", t->line_pos,
4448 + "line:", t->line, "pos:", t->line_pos,
4449 "only =~ and == are allowed in the condition");
4452 @@ -456,51 +478,51 @@
4454 } else if (t->in_key) {
4458 buffer_copy_string_len(token, t->input + t->offset, 1);
4464 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4465 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4466 "source:", t->source,
4467 - "line:", t->line, "pos:", t->line_pos,
4468 + "line:", t->line, "pos:", t->line_pos,
4469 "unexpected equal-sign: =");
4478 if (t->input[t->offset + 1] == '=') {
4482 buffer_copy_string(token, "!=");
4486 } else if (t->input[t->offset + 1] == '~') {
4490 buffer_copy_string(token, "!~");
4495 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4496 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4497 "source:", t->source,
4498 - "line:", t->line, "pos:", t->line_pos,
4499 + "line:", t->line, "pos:", t->line_pos,
4500 "only !~ and != are allowed in the condition");
4506 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4507 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4508 "source:", t->source,
4509 - "line:", t->line, "pos:", t->line_pos,
4510 + "line:", t->line, "pos:", t->line_pos,
4511 "unexpected exclamation-marks: !");
4519 @@ -546,10 +568,10 @@
4521 if (t->in_brace > 0) {
4525 buffer_copy_string(token, "(COMMA)");
4532 @@ -557,70 +579,70 @@
4533 /* search for the terminating " */
4534 start = t->input + t->offset + 1;
4535 buffer_copy_string(token, "");
4538 for (i = 1; t->input[t->offset + i]; i++) {
4539 if (t->input[t->offset + i] == '\\' &&
4540 t->input[t->offset + i + 1] == '"') {
4543 buffer_append_string_len(token, start, t->input + t->offset + i - start);
4546 start = t->input + t->offset + i + 1;
4557 if (t->input[t->offset + i] == '"') {
4561 buffer_append_string_len(token, start, t->input + t->offset + i - start);
4568 if (t->input[t->offset + i] == '\0') {
4571 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4573 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4574 "source:", t->source,
4575 - "line:", t->line, "pos:", t->line_pos,
4576 + "line:", t->line, "pos:", t->line_pos,
4577 "missing closing quote");
4585 t->line_pos += i + 1;
4597 buffer_copy_string(token, "(");
4607 buffer_copy_string(token, ")");
4618 buffer_copy_string(token, "$");
4624 @@ -637,115 +659,107 @@
4633 buffer_copy_string(token, "{");
4646 buffer_copy_string(token, "}");
4658 buffer_copy_string(token, "[");
4671 buffer_copy_string(token, "]");
4676 t->line_pos += config_skip_comment(t);
4682 - for (i = 0; t->input[t->offset + i] &&
4683 + for (i = 0; t->input[t->offset + i] &&
4684 (isalpha((unsigned char)t->input[t->offset + i])
4688 if (i && t->input[t->offset + i]) {
4689 tid = TK_SRVVARNAME;
4690 buffer_copy_string_len(token, t->input + t->offset, i);
4697 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4698 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4699 "source:", t->source,
4700 - "line:", t->line, "pos:", t->line_pos,
4701 + "line:", t->line, "pos:", t->line_pos,
4702 "invalid character in condition");
4705 } else if (isdigit((unsigned char)c)) {
4706 /* take all digits */
4707 for (i = 0; t->input[t->offset + i] && isdigit((unsigned char)t->input[t->offset + i]); i++);
4710 /* was there it least a digit ? */
4711 - if (i && t->input[t->offset + i]) {
4716 buffer_copy_string_len(token, t->input + t->offset, i);
4723 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4724 - "source:", t->source,
4725 - "line:", t->line, "pos:", t->line_pos,
4726 - "unexpected EOF");
4731 /* the key might consist of [-.0-9a-z] */
4732 - for (i = 0; t->input[t->offset + i] &&
4733 - (isalnum((unsigned char)t->input[t->offset + i]) ||
4734 + for (i = 0; t->input[t->offset + i] &&
4735 + (isalnum((unsigned char)t->input[t->offset + i]) ||
4736 t->input[t->offset + i] == '.' ||
4737 t->input[t->offset + i] == '_' || /* for env.* */
4738 t->input[t->offset + i] == '-'
4742 if (i && t->input[t->offset + i]) {
4743 buffer_copy_string_len(token, t->input + t->offset, i);
4745 - if (strcmp(token->ptr, "include") == 0) {
4747 + if (buffer_is_equal_string(token, CONST_STR_LEN("include"))) {
4749 - } else if (strcmp(token->ptr, "include_shell") == 0) {
4750 + } else if (buffer_is_equal_string(token, CONST_STR_LEN("include_shell"))) {
4751 tid = TK_INCLUDE_SHELL;
4752 - } else if (strcmp(token->ptr, "global") == 0) {
4753 + } else if (buffer_is_equal_string(token, CONST_STR_LEN("global"))) {
4755 - } else if (strcmp(token->ptr, "else") == 0) {
4756 + } else if (buffer_is_equal_string(token, CONST_STR_LEN("else"))) {
4767 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4768 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4769 "source:", t->source,
4770 - "line:", t->line, "pos:", t->line_pos,
4771 + "line:", t->line, "pos:", t->line_pos,
4772 "invalid character in variable name");
4775 @@ -753,16 +767,16 @@
4784 - log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
4785 + log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
4786 "source:", t->source,
4787 "line:", t->line, "pos:", t->line_pos,
4788 token, token->used - 1, tid);
4793 } else if (t->offset < t->size) {
4794 fprintf(stderr, "%s.%d: %d, %s\n",
4795 @@ -781,10 +795,11 @@
4796 pParser = configparserAlloc( malloc );
4797 lasttoken = buffer_init();
4798 token = buffer_init();
4800 while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
4801 buffer_copy_string_buffer(lasttoken, token);
4802 configparser(pParser, token_id, token, context);
4805 token = buffer_init();
4808 @@ -797,14 +812,14 @@
4811 configparserFree(pParser, free);
4815 - log_error_write(srv, __FILE__, __LINE__, "sb",
4816 + log_error_write(srv, __FILE__, __LINE__, "sb",
4817 "configfile parser failed:", lasttoken);
4818 } else if (context->ok == 0) {
4819 - log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
4820 + log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
4821 "source:", t->source,
4822 - "line:", t->line, "pos:", t->line_pos,
4823 + "line:", t->line, "pos:", t->line_pos,
4824 "parser failed somehow near here:", lasttoken);
4839 if (0 != stream_open(&s, filename)) {
4840 - log_error_write(srv, __FILE__, __LINE__, "sbss",
4841 + log_error_write(srv, __FILE__, __LINE__, "sbss",
4842 "opening configfile ", filename, "failed:", strerror(errno));
4846 char oldpwd[PATH_MAX];
4848 if (NULL == getcwd(oldpwd, sizeof(oldpwd))) {
4849 - log_error_write(srv, __FILE__, __LINE__, "s",
4850 + log_error_write(srv, __FILE__, __LINE__, "s",
4851 "cannot get cwd", strerror(errno));
4857 if (0 != proc_open_buffer(&proc, cmd, NULL, out, NULL)) {
4858 - log_error_write(srv, __FILE__, __LINE__, "sbss",
4859 + log_error_write(srv, __FILE__, __LINE__, "sbss",
4860 "opening", source, "failed:", strerror(errno));
4863 @@ -896,13 +911,12 @@
4864 static void context_init(server *srv, config_t *context) {
4867 - context->configs_stack = array_init();
4868 - context->configs_stack->is_weakref = 1;
4869 + context->configs_stack = buffer_ptr_init(NULL);
4870 context->basedir = buffer_init();
4873 static void context_free(config_t *context) {
4874 - array_free(context->configs_stack);
4875 + buffer_ptr_free(context->configs_stack);
4876 buffer_free(context->basedir);
4879 @@ -918,18 +932,15 @@
4880 context_init(srv, &context);
4881 context.all_configs = srv->config_context;
4890 + /* use the current dir as basedir for all other includes
4892 + pos = strrchr(fn, DIR_SEPERATOR);
4895 buffer_copy_string_len(context.basedir, fn, pos - fn + 1);
4900 dc = data_config_init();
4901 buffer_copy_string(dc->key, "global");
4904 dpid->value = getpid();
4905 buffer_copy_string(dpid->key, "var.PID");
4906 array_insert_unique(srv->config, (data_unset *)dpid);
4909 dcwd = data_string_init();
4910 buffer_prepare_copy(dcwd->value, 1024);
4911 if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) {
4918 if (NULL != (modules = (data_array *)array_get_element(srv->config, "server.modules"))) {
4920 data_array *prepends;
4921 @@ -1026,22 +1037,23 @@
4922 buffer_copy_string(modules->key, "server.modules");
4923 array_insert_unique(srv->config, (data_unset *)modules);
4928 if (0 != config_insert(srv)) {
4937 int config_set_defaults(server *srv) {
4939 specific_config *s = srv->config_storage[0];
4940 struct stat st1, st2;
4942 - struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
4945 + struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
4947 /* - poll is most reliable
4948 * - select works everywhere
4949 * - linux-* are experimental
4950 @@ -1067,20 +1079,21 @@
4952 { FDEVENT_HANDLER_UNSET, NULL }
4956 - if (buffer_is_empty(s->document_root)) {
4957 - log_error_write(srv, __FILE__, __LINE__, "s",
4958 - "a default document-root has to be set");
4964 + if (buffer_is_empty(s->document_root)) {
4965 + log_error_write(srv, __FILE__, __LINE__, "s",
4966 + "a default document-root has to be set");
4971 if (buffer_is_empty(srv->srvconf.changeroot)) {
4972 - if (-1 == stat(s->document_root->ptr, &st1)) {
4973 - log_error_write(srv, __FILE__, __LINE__, "sb",
4974 + pathname_unix2local(s->document_root);
4975 + if (-1 == stat(s->document_root->ptr, &st1)) {
4976 + log_error_write(srv, __FILE__, __LINE__, "sbs",
4977 "base-docroot doesn't exist:",
4978 - s->document_root);
4979 + s->document_root, strerror(errno));
4983 @@ -1088,18 +1101,18 @@
4984 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.changeroot);
4985 buffer_append_string_buffer(srv->tmp_buf, s->document_root);
4987 - if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
4988 - log_error_write(srv, __FILE__, __LINE__, "sb",
4989 + if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
4990 + log_error_write(srv, __FILE__, __LINE__, "sb",
4991 "base-docroot doesn't exist:",
5000 - buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
5002 - buffer_to_lower(srv->tmp_buf);
5003 + buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
5005 + buffer_to_lower(srv->tmp_buf);
5007 if (0 == stat(srv->tmp_buf->ptr, &st1)) {
5009 @@ -1107,68 +1120,68 @@
5010 is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);
5012 /* lower-case existed, check upper-case */
5013 - buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
5014 + buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
5016 - buffer_to_upper(srv->tmp_buf);
5017 + buffer_to_upper(srv->tmp_buf);
5019 /* we have to handle the special case that upper and lower-casing results in the same filename
5020 * as in server.document-root = "/" or "/12345/" */
5022 if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
5023 - /* lower-casing and upper-casing didn't result in
5024 - * an other filename, no need to stat(),
5025 + /* lower-casing and upper-casing didn't result in
5026 + * an other filename, no need to stat(),
5027 * just assume it is case-sensitive. */
5029 s->force_lowercase_filenames = 0;
5030 - } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
5031 + } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
5033 + /* upper case exists too, doesn't the FS handle this ? */
5035 + /* upper and lower have the same inode -> case-insensitve FS */
5037 + if (st1.st_ino == st2.st_ino) {
5038 + /* upper and lower have the same inode -> case-insensitve FS */
5040 + s->force_lowercase_filenames = 1;
5045 - /* upper case exists too, doesn't the FS handle this ? */
5047 - /* upper and lower have the same inode -> case-insensitve FS */
5049 - if (st1.st_ino == st2.st_ino) {
5050 - /* upper and lower have the same inode -> case-insensitve FS */
5052 - s->force_lowercase_filenames = 1;
5057 if (srv->srvconf.port == 0) {
5058 srv->srvconf.port = s->is_ssl ? 443 : 80;
5062 if (srv->srvconf.event_handler->used == 0) {
5063 /* choose a good default
5065 - * the event_handler list is sorted by 'goodness'
5067 + * the event_handler list is sorted by 'goodness'
5068 * taking the first available should be the best solution
5070 srv->event_handler = event_handlers[0].et;
5073 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
5074 - log_error_write(srv, __FILE__, __LINE__, "s",
5075 + log_error_write(srv, __FILE__, __LINE__, "s",
5076 "sorry, there is no event handler for this system");
5087 for (i = 0; event_handlers[i].name; i++) {
5088 if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) {
5089 srv->event_handler = event_handlers[i].et;
5095 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
5096 - log_error_write(srv, __FILE__, __LINE__, "sb",
5097 - "the selected event-handler in unknown or not supported:",
5098 + log_error_write(srv, __FILE__, __LINE__, "sb",
5099 + "the selected event-handler in unknown or not supported:",
5100 srv->srvconf.event_handler );
5106 @@ -1176,19 +1189,19 @@
5108 if (buffer_is_empty(s->ssl_pemfile)) {
5109 /* PEM file is require */
5111 - log_error_write(srv, __FILE__, __LINE__, "s",
5113 + log_error_write(srv, __FILE__, __LINE__, "s",
5114 "ssl.pemfile has to be set");
5120 - log_error_write(srv, __FILE__, __LINE__, "s",
5121 + log_error_write(srv, __FILE__, __LINE__, "s",
5122 "ssl support is missing, recompile with --with-openssl");
5132 --- ../lighttpd-1.4.11/src/configfile.h 2005-08-23 17:36:12.000000000 +0300
5133 +++ lighttpd-1.5.0/src/configfile.h 2006-09-07 00:57:05.000000000 +0300
5138 - array *configs_stack; /* to parse nested block */
5139 + buffer_ptr *configs_stack; /* to parse nested block */
5140 data_config *current; /* current started with { */
5144 int config_parse_file(server *srv, config_t *context, const char *fn);
5145 int config_parse_cmd(server *srv, config_t *context, const char *cmd);
5146 data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2);
5147 +void config_cond_cache_reset(server *srv, connection *con);
5150 --- ../lighttpd-1.4.11/src/configparser.c 2006-02-01 19:51:15.000000000 +0200
5151 +++ lighttpd-1.5.0/src/configparser.c 2006-09-07 00:57:07.000000000 +0300
5153 dc->parent = ctx->current;
5154 array_insert_unique(dc->parent->childs, (data_unset *)dc);
5156 - array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
5157 + buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
5161 static data_config *configparser_pop(config_t *ctx) {
5162 data_config *old = ctx->current;
5163 - ctx->current = (data_config *) array_pop(ctx->configs_stack);
5164 + ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
5168 /* return a copied variable */
5169 static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
5170 - if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
5173 - if (NULL != (env = getenv(key->ptr + 4))) {
5175 - ds = data_string_init();
5176 - buffer_append_string(ds->value, env);
5177 - return (data_unset *)ds;
5180 - fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
5191 - fprintf(stderr, "get var %s\n", key->ptr);
5192 + fprintf(stderr, "get var %s\n", key->ptr);
5194 - for (dc = ctx->current; dc; dc = dc->parent) {
5195 + for (dc = ctx->current; dc; dc = dc->parent) {
5197 - fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5198 - array_print(dc->value, 0);
5199 + fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5200 + array_print(dc->value, 0);
5202 - if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5203 - return du->copy(du);
5205 + if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5206 + return du->copy(du);
5208 - fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
5215 /* op1 is to be eat/return by this function, op1->key is not cared
5216 @@ -124,14 +106,14 @@
5220 -#line 128 "configparser.c"
5221 +#line 110 "configparser.c"
5222 /* Next is all token values, in a form suitable for use by makeheaders.
5223 ** This section will be null unless lemon is run with the -m switch.
5227 ** These constants (all generated automatically by the parser generator)
5228 ** specify the various kinds of tokens (terminals) that the parser
5232 ** Each symbol here is a terminal symbol in the grammar.
5235 ** and nonterminals. "int" is used otherwise.
5236 ** YYNOCODE is a number of type YYCODETYPE which corresponds
5237 ** to no legal terminal or nonterminal number. This
5238 -** number is used to fill in empty slots of the hash
5239 +** number is used to fill in empty slots of the hash
5241 ** YYFALLBACK If defined, this indicates that one or more tokens
5242 ** have fall-back values which should be used if the
5244 ** and nonterminal numbers. "unsigned char" is
5245 ** used if there are fewer than 250 rules and
5246 ** states combined. "int" is used otherwise.
5247 -** configparserTOKENTYPE is the data type used for minor tokens given
5248 +** configparserTOKENTYPE is the data type used for minor tokens given
5249 ** directly to the parser from the tokenizer.
5250 ** YYMINORTYPE is the data type used for all minor tokens.
5251 ** This is typically a union of many types, one of
5253 #define configparserARG_PDECL ,config_t *ctx
5254 #define configparserARG_FETCH config_t *ctx = yypParser->ctx
5255 #define configparserARG_STORE yypParser->ctx = ctx
5256 -#define YYNSTATE 62
5258 +#define YYNSTATE 63
5260 #define YYERRORSYMBOL 26
5261 #define YYERRSYMDT yy95
5262 #define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
5264 /* Next are that tables used to determine what action to take based on the
5265 ** current state and lookahead token. These tables are used to implement
5266 ** functions that take a state number and lookahead value and return an
5270 ** Suppose the action integer is N. Then the action is determined as
5273 ** If the index value yy_shift_ofst[S]+X is out of range or if the value
5274 ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
5275 ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
5276 -** and that yy_default[S] should be used instead.
5277 +** and that yy_default[S] should be used instead.
5279 ** The formula above is for computing the action when the lookahead is
5280 ** a terminal symbol. If the lookahead is a non-terminal (as occurs after
5281 @@ -248,67 +230,69 @@
5282 ** yy_default[] Default action for each state.
5284 static YYACTIONTYPE yy_action[] = {
5285 - /* 0 */ 2, 3, 4, 5, 13, 14, 62, 15, 7, 44,
5286 - /* 10 */ 20, 86, 16, 45, 28, 48, 40, 10, 39, 25,
5287 - /* 20 */ 22, 49, 45, 8, 15, 102, 1, 20, 28, 18,
5288 - /* 30 */ 57, 59, 19, 25, 22, 39, 19, 61, 98, 45,
5289 - /* 40 */ 20, 6, 23, 24, 26, 28, 35, 57, 59, 12,
5290 - /* 50 */ 25, 22, 28, 27, 36, 87, 29, 25, 22, 33,
5291 - /* 60 */ 15, 30, 31, 20, 28, 38, 9, 17, 37, 25,
5292 - /* 70 */ 22, 39, 42, 43, 10, 45, 11, 53, 54, 55,
5293 - /* 80 */ 56, 28, 52, 57, 59, 34, 25, 22, 28, 27,
5294 - /* 90 */ 32, 88, 41, 25, 22, 33, 28, 48, 46, 28,
5295 - /* 100 */ 48, 25, 22, 58, 25, 22, 60, 21, 19, 47,
5296 - /* 110 */ 51, 50, 25, 22, 88, 88, 93,
5297 + /* 0 */ 2, 3, 4, 5, 13, 14, 63, 15, 7, 45,
5298 + /* 10 */ 20, 88, 16, 46, 28, 49, 41, 10, 40, 25,
5299 + /* 20 */ 22, 50, 46, 8, 15, 104, 1, 20, 28, 18,
5300 + /* 30 */ 58, 60, 6, 25, 22, 40, 47, 62, 11, 46,
5301 + /* 40 */ 20, 9, 23, 24, 26, 29, 89, 58, 60, 10,
5302 + /* 50 */ 17, 38, 28, 27, 37, 19, 30, 25, 22, 34,
5303 + /* 60 */ 15, 100, 20, 20, 23, 24, 26, 12, 19, 31,
5304 + /* 70 */ 32, 40, 19, 44, 43, 46, 95, 35, 90, 89,
5305 + /* 80 */ 28, 49, 42, 58, 60, 25, 22, 59, 28, 27,
5306 + /* 90 */ 33, 48, 52, 25, 22, 34, 28, 49, 51, 28,
5307 + /* 100 */ 36, 25, 22, 61, 25, 22, 89, 28, 39, 89,
5308 + /* 110 */ 89, 89, 25, 22, 54, 55, 56, 57, 89, 28,
5309 + /* 120 */ 53, 21, 89, 89, 25, 22, 25, 22,
5311 static YYCODETYPE yy_lookahead[] = {
5312 /* 0 */ 29, 30, 31, 32, 33, 34, 0, 1, 44, 38,
5313 /* 10 */ 4, 15, 41, 16, 35, 36, 45, 46, 12, 40,
5314 /* 20 */ 41, 42, 16, 15, 1, 27, 28, 4, 35, 36,
5315 - /* 30 */ 24, 25, 5, 40, 41, 12, 5, 14, 11, 16,
5316 - /* 40 */ 4, 1, 6, 7, 8, 35, 36, 24, 25, 28,
5317 - /* 50 */ 40, 41, 35, 36, 37, 15, 39, 40, 41, 42,
5318 - /* 60 */ 1, 9, 10, 4, 35, 36, 38, 2, 3, 40,
5319 - /* 70 */ 41, 12, 28, 14, 46, 16, 13, 20, 21, 22,
5320 - /* 80 */ 23, 35, 36, 24, 25, 11, 40, 41, 35, 36,
5321 - /* 90 */ 37, 13, 13, 40, 41, 42, 35, 36, 17, 35,
5322 - /* 100 */ 36, 40, 41, 42, 40, 41, 42, 35, 5, 18,
5323 - /* 110 */ 43, 19, 40, 41, 47, 47, 13,
5324 + /* 30 */ 24, 25, 1, 40, 41, 12, 17, 14, 13, 16,
5325 + /* 40 */ 4, 38, 6, 7, 8, 9, 15, 24, 25, 46,
5326 + /* 50 */ 2, 3, 35, 36, 37, 5, 39, 40, 41, 42,
5327 + /* 60 */ 1, 11, 4, 4, 6, 7, 8, 28, 5, 9,
5328 + /* 70 */ 10, 12, 5, 14, 28, 16, 13, 11, 13, 47,
5329 + /* 80 */ 35, 36, 13, 24, 25, 40, 41, 42, 35, 36,
5330 + /* 90 */ 37, 18, 43, 40, 41, 42, 35, 36, 19, 35,
5331 + /* 100 */ 36, 40, 41, 42, 40, 41, 47, 35, 36, 47,
5332 + /* 110 */ 47, 47, 40, 41, 20, 21, 22, 23, 47, 35,
5333 + /* 120 */ 36, 35, 47, 47, 40, 41, 40, 41,
5335 #define YY_SHIFT_USE_DFLT (-5)
5336 static signed char yy_shift_ofst[] = {
5337 - /* 0 */ -5, 6, -5, -5, -5, 40, -4, 8, -3, -5,
5338 - /* 10 */ 63, -5, 23, -5, -5, -5, 65, 36, 31, 36,
5339 - /* 20 */ -5, -5, -5, -5, -5, -5, 36, 27, -5, 52,
5340 - /* 30 */ -5, 36, -5, 74, 36, 31, -5, 36, 31, 78,
5341 - /* 40 */ 79, -5, 59, -5, -5, 81, 91, 36, 31, 92,
5342 - /* 50 */ 57, 36, 103, -5, -5, -5, -5, 36, -5, 36,
5344 + /* 0 */ -5, 6, -5, -5, -5, 31, -4, 8, -3, -5,
5345 + /* 10 */ 25, -5, 23, -5, -5, -5, 48, 58, 67, 58,
5346 + /* 20 */ -5, -5, -5, -5, -5, -5, 36, 50, -5, -5,
5347 + /* 30 */ 60, -5, 58, -5, 66, 58, 67, -5, 58, 67,
5348 + /* 40 */ 65, 69, -5, 59, -5, -5, 19, 73, 58, 67,
5349 + /* 50 */ 79, 94, 58, 63, -5, -5, -5, -5, 58, -5,
5350 + /* 60 */ 58, -5, -5,
5352 #define YY_REDUCE_USE_DFLT (-37)
5353 static signed char yy_reduce_ofst[] = {
5354 - /* 0 */ -2, -29, -37, -37, -37, -36, -37, -37, 28, -37,
5355 - /* 10 */ -37, 21, -29, -37, -37, -37, -37, -7, -37, 72,
5356 + /* 0 */ -2, -29, -37, -37, -37, -36, -37, -37, 3, -37,
5357 + /* 10 */ -37, 39, -29, -37, -37, -37, -37, -7, -37, 86,
5358 /* 20 */ -37, -37, -37, -37, -37, -37, 17, -37, -37, -37,
5359 - /* 30 */ -37, 53, -37, -37, 10, -37, -37, 29, -37, -37,
5360 - /* 40 */ -37, 44, -29, -37, -37, -37, -37, -21, -37, -37,
5361 - /* 50 */ 67, 46, -37, -37, -37, -37, -37, 61, -37, 64,
5362 - /* 60 */ -37, -37,
5363 + /* 30 */ -37, -37, 53, -37, -37, 64, -37, -37, 72, -37,
5364 + /* 40 */ -37, -37, 46, -29, -37, -37, -37, -37, -21, -37,
5365 + /* 50 */ -37, 49, 84, -37, -37, -37, -37, -37, 45, -37,
5366 + /* 60 */ 61, -37, -37,
5368 static YYACTIONTYPE yy_default[] = {
5369 - /* 0 */ 64, 101, 63, 65, 66, 101, 67, 101, 101, 90,
5370 - /* 10 */ 101, 64, 101, 68, 69, 70, 101, 101, 71, 101,
5371 - /* 20 */ 73, 74, 76, 77, 78, 79, 101, 84, 75, 101,
5372 - /* 30 */ 80, 82, 81, 101, 101, 85, 83, 101, 72, 101,
5373 - /* 40 */ 101, 64, 101, 89, 91, 101, 101, 101, 98, 101,
5374 - /* 50 */ 101, 101, 101, 94, 95, 96, 97, 101, 99, 101,
5376 + /* 0 */ 65, 103, 64, 66, 67, 103, 68, 103, 103, 92,
5377 + /* 10 */ 103, 65, 103, 69, 70, 71, 103, 103, 72, 103,
5378 + /* 20 */ 74, 75, 77, 78, 79, 80, 103, 86, 76, 81,
5379 + /* 30 */ 103, 82, 84, 83, 103, 103, 87, 85, 103, 73,
5380 + /* 40 */ 103, 103, 65, 103, 91, 93, 103, 103, 103, 100,
5381 + /* 50 */ 103, 103, 103, 103, 96, 97, 98, 99, 103, 101,
5382 + /* 60 */ 103, 102, 94,
5384 #define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
5386 /* The next table maps tokens into fallback tokens. If a construct
5387 ** like the following:
5390 ** %fallback ID X Y Z.
5392 ** appears in the grammer, then ID becomes a fallback token for X, Y,
5393 @@ -359,10 +343,10 @@
5399 ** Turn parser tracing on by giving a stream to which to write the trace
5400 ** and a prompt to preface each trace message. Tracing is turned off
5401 -** by making either argument NULL
5402 +** by making either argument NULL
5408 /* For tracing shifts, the names of all terminals and nonterminals
5409 ** are required. The following table supplies these names */
5410 -static const char *yyTokenName[] = {
5411 +static const char *yyTokenName[] = {
5412 "$", "EOL", "ASSIGN", "APPEND",
5413 "LKEY", "PLUS", "STRING", "INTEGER",
5414 "LPARAN", "RPARAN", "COMMA", "ARRAY_ASSIGN",
5415 @@ -425,27 +409,28 @@
5416 /* 15 */ "value ::= STRING",
5417 /* 16 */ "value ::= INTEGER",
5418 /* 17 */ "value ::= array",
5419 - /* 18 */ "array ::= LPARAN aelements RPARAN",
5420 - /* 19 */ "aelements ::= aelements COMMA aelement",
5421 - /* 20 */ "aelements ::= aelements COMMA",
5422 - /* 21 */ "aelements ::= aelement",
5423 - /* 22 */ "aelement ::= expression",
5424 - /* 23 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5425 - /* 24 */ "eols ::= EOL",
5426 - /* 25 */ "eols ::=",
5427 - /* 26 */ "globalstart ::= GLOBAL",
5428 - /* 27 */ "global ::= globalstart LCURLY metalines RCURLY",
5429 - /* 28 */ "condlines ::= condlines eols ELSE condline",
5430 - /* 29 */ "condlines ::= condline",
5431 - /* 30 */ "condline ::= context LCURLY metalines RCURLY",
5432 - /* 31 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5433 - /* 32 */ "cond ::= EQ",
5434 - /* 33 */ "cond ::= MATCH",
5435 - /* 34 */ "cond ::= NE",
5436 - /* 35 */ "cond ::= NOMATCH",
5437 - /* 36 */ "stringop ::= expression",
5438 - /* 37 */ "include ::= INCLUDE stringop",
5439 - /* 38 */ "include_shell ::= INCLUDE_SHELL stringop",
5440 + /* 18 */ "array ::= LPARAN RPARAN",
5441 + /* 19 */ "array ::= LPARAN aelements RPARAN",
5442 + /* 20 */ "aelements ::= aelements COMMA aelement",
5443 + /* 21 */ "aelements ::= aelements COMMA",
5444 + /* 22 */ "aelements ::= aelement",
5445 + /* 23 */ "aelement ::= expression",
5446 + /* 24 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5447 + /* 25 */ "eols ::= EOL",
5448 + /* 26 */ "eols ::=",
5449 + /* 27 */ "globalstart ::= GLOBAL",
5450 + /* 28 */ "global ::= globalstart LCURLY metalines RCURLY",
5451 + /* 29 */ "condlines ::= condlines eols ELSE condline",
5452 + /* 30 */ "condlines ::= condline",
5453 + /* 31 */ "condline ::= context LCURLY metalines RCURLY",
5454 + /* 32 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5455 + /* 33 */ "cond ::= EQ",
5456 + /* 34 */ "cond ::= MATCH",
5457 + /* 35 */ "cond ::= NE",
5458 + /* 36 */ "cond ::= NOMATCH",
5459 + /* 37 */ "stringop ::= expression",
5460 + /* 38 */ "include ::= INCLUDE stringop",
5461 + /* 39 */ "include_shell ::= INCLUDE_SHELL stringop",
5471 ** This function allocates a new parser.
5472 ** The only argument is a pointer to a function which works like
5475 /* Here is inserted the actions which take place when a
5476 ** terminal or non-terminal is destroyed. This can happen
5477 ** when the symbol is popped from the stack during a
5478 - ** reduce or during error processing or when a parser is
5479 + ** reduce or during error processing or when a parser is
5480 ** being destroyed before it is finished parsing.
5482 ** Note: during a reduce, the only symbols destroyed are those
5483 @@ -528,44 +513,44 @@
5487 -#line 160 "./configparser.y"
5488 +#line 143 "./configparser.y"
5489 { buffer_free((yypminor->yy0)); }
5490 -#line 533 "configparser.c"
5491 +#line 518 "configparser.c"
5494 -#line 151 "./configparser.y"
5495 +#line 134 "./configparser.y"
5496 { (yypminor->yy41)->free((yypminor->yy41)); }
5497 -#line 538 "configparser.c"
5498 +#line 523 "configparser.c"
5501 -#line 152 "./configparser.y"
5502 +#line 135 "./configparser.y"
5503 { (yypminor->yy41)->free((yypminor->yy41)); }
5504 -#line 543 "configparser.c"
5505 +#line 528 "configparser.c"
5508 -#line 153 "./configparser.y"
5509 +#line 136 "./configparser.y"
5510 { (yypminor->yy41)->free((yypminor->yy41)); }
5511 -#line 548 "configparser.c"
5512 +#line 533 "configparser.c"
5515 -#line 154 "./configparser.y"
5516 +#line 137 "./configparser.y"
5517 { array_free((yypminor->yy40)); }
5518 -#line 553 "configparser.c"
5519 +#line 538 "configparser.c"
5522 -#line 155 "./configparser.y"
5523 +#line 138 "./configparser.y"
5524 { array_free((yypminor->yy40)); }
5525 -#line 558 "configparser.c"
5526 +#line 543 "configparser.c"
5529 -#line 156 "./configparser.y"
5530 +#line 139 "./configparser.y"
5531 { buffer_free((yypminor->yy43)); }
5532 -#line 563 "configparser.c"
5533 +#line 548 "configparser.c"
5536 -#line 157 "./configparser.y"
5537 +#line 140 "./configparser.y"
5538 { buffer_free((yypminor->yy43)); }
5539 -#line 568 "configparser.c"
5540 +#line 553 "configparser.c"
5542 default: break; /* If no destructor action specified: do nothing */
5550 ** Deallocate and destroy a parser. Destructors are all called for
5551 ** all stack elements before shutting the parser down.
5556 int stateno = pParser->yystack[pParser->yyidx].stateno;
5559 /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
5560 i = yy_shift_ofst[stateno];
5561 if( i==YY_SHIFT_USE_DFLT ){
5565 int stateno = pParser->yystack[pParser->yyidx].stateno;
5568 i = yy_reduce_ofst[stateno];
5569 if( i==YY_REDUCE_USE_DFLT ){
5570 return yy_default[stateno];
5580 configparserARG_FETCH;
5581 yymsp = &yypParser->yystack[yypParser->yyidx];
5583 - if( yyTraceFILE && yyruleno>=0
5584 + if( yyTraceFILE && yyruleno>=0
5585 && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
5586 fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
5587 yyRuleName[yyruleno]);
5589 /* No destructor defined for global */
5592 -#line 134 "./configparser.y"
5593 +#line 116 "./configparser.y"
5594 { yymsp[-1].minor.yy78 = NULL; }
5595 -#line 837 "configparser.c"
5596 +#line 823 "configparser.c"
5597 yy_destructor(1,&yymsp[0].minor);
5600 @@ -847,10 +833,15 @@
5601 yy_destructor(1,&yymsp[0].minor);
5604 -#line 162 "./configparser.y"
5605 +#line 145 "./configparser.y"
5607 buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5608 - if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5609 + if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5610 + fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
5611 + ctx->current->context_ndx,
5612 + ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5614 + } else if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5615 array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5616 yymsp[0].minor.yy41 = NULL;
5618 @@ -864,16 +855,21 @@
5619 buffer_free(yymsp[-2].minor.yy43);
5620 yymsp[-2].minor.yy43 = NULL;
5622 -#line 867 "configparser.c"
5623 +#line 858 "configparser.c"
5624 yy_destructor(2,&yymsp[-1].minor);
5627 -#line 179 "./configparser.y"
5628 +#line 167 "./configparser.y"
5630 array *vars = ctx->current->value;
5633 - if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5634 + if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5635 + fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
5636 + ctx->current->context_ndx,
5637 + ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5639 + } else if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5640 /* exists in current block */
5641 du = configparser_merge_data(du, yymsp[0].minor.yy41);
5644 buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5645 array_replace(vars, du);
5647 + yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5648 } else if (NULL != (du = configparser_get_variable(ctx, yymsp[-2].minor.yy43))) {
5649 du = configparser_merge_data(du, yymsp[0].minor.yy41);
5651 @@ -892,22 +889,20 @@
5652 buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5653 array_insert_unique(ctx->current->value, du);
5655 + yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5657 - fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n",
5658 - ctx->current->context_ndx,
5659 - ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5661 + buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5662 + array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5664 buffer_free(yymsp[-2].minor.yy43);
5665 yymsp[-2].minor.yy43 = NULL;
5666 - yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5667 yymsp[0].minor.yy41 = NULL;
5669 -#line 906 "configparser.c"
5670 +#line 901 "configparser.c"
5671 yy_destructor(3,&yymsp[-1].minor);
5674 -#line 214 "./configparser.y"
5675 +#line 206 "./configparser.y"
5677 if (strchr(yymsp[0].minor.yy0->ptr, '.') == NULL) {
5678 yygotominor.yy43 = buffer_init_string("var.");
5679 @@ -919,10 +914,10 @@
5680 yymsp[0].minor.yy0 = NULL;
5683 -#line 922 "configparser.c"
5684 +#line 917 "configparser.c"
5687 -#line 226 "./configparser.y"
5688 +#line 218 "./configparser.y"
5690 yygotominor.yy41 = configparser_merge_data(yymsp[-2].minor.yy41, yymsp[0].minor.yy41);
5691 if (NULL == yygotominor.yy41) {
5692 @@ -932,21 +927,38 @@
5693 yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5694 yymsp[0].minor.yy41 = NULL;
5696 -#line 935 "configparser.c"
5697 +#line 930 "configparser.c"
5698 yy_destructor(5,&yymsp[-1].minor);
5701 -#line 236 "./configparser.y"
5702 +#line 228 "./configparser.y"
5704 yygotominor.yy41 = yymsp[0].minor.yy41;
5705 yymsp[0].minor.yy41 = NULL;
5707 -#line 944 "configparser.c"
5708 +#line 939 "configparser.c"
5711 -#line 241 "./configparser.y"
5712 +#line 233 "./configparser.y"
5714 - yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43);
5715 + if (strncmp(yymsp[0].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5718 + if (NULL != (env = getenv(yymsp[0].minor.yy43->ptr + 4))) {
5720 + ds = data_string_init();
5721 + buffer_append_string(ds->value, env);
5722 + yygotominor.yy41 = (data_unset *)ds;
5725 + yygotominor.yy41 = NULL;
5726 + fprintf(stderr, "Undefined env variable: %s\n", yymsp[0].minor.yy43->ptr + 4);
5729 + } else if (NULL == (yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43))) {
5730 + fprintf(stderr, "Undefined config variable: %s\n", yymsp[0].minor.yy43->ptr);
5733 if (!yygotominor.yy41) {
5734 /* make a dummy so it won't crash */
5735 yygotominor.yy41 = (data_unset *)data_string_init();
5736 @@ -954,50 +966,59 @@
5737 buffer_free(yymsp[0].minor.yy43);
5738 yymsp[0].minor.yy43 = NULL;
5740 -#line 957 "configparser.c"
5741 +#line 969 "configparser.c"
5744 -#line 251 "./configparser.y"
5745 +#line 260 "./configparser.y"
5747 yygotominor.yy41 = (data_unset *)data_string_init();
5748 buffer_copy_string_buffer(((data_string *)(yygotominor.yy41))->value, yymsp[0].minor.yy0);
5749 buffer_free(yymsp[0].minor.yy0);
5750 yymsp[0].minor.yy0 = NULL;
5752 -#line 967 "configparser.c"
5753 +#line 979 "configparser.c"
5756 -#line 258 "./configparser.y"
5757 +#line 267 "./configparser.y"
5759 yygotominor.yy41 = (data_unset *)data_integer_init();
5760 ((data_integer *)(yygotominor.yy41))->value = strtol(yymsp[0].minor.yy0->ptr, NULL, 10);
5761 buffer_free(yymsp[0].minor.yy0);
5762 yymsp[0].minor.yy0 = NULL;
5764 -#line 977 "configparser.c"
5765 +#line 989 "configparser.c"
5768 -#line 264 "./configparser.y"
5769 +#line 273 "./configparser.y"
5771 yygotominor.yy41 = (data_unset *)data_array_init();
5772 array_free(((data_array *)(yygotominor.yy41))->value);
5773 ((data_array *)(yygotominor.yy41))->value = yymsp[0].minor.yy40;
5774 yymsp[0].minor.yy40 = NULL;
5776 -#line 987 "configparser.c"
5777 +#line 999 "configparser.c"
5780 -#line 270 "./configparser.y"
5781 +#line 279 "./configparser.y"
5783 + yygotominor.yy40 = array_init();
5785 +#line 1006 "configparser.c"
5786 + yy_destructor(8,&yymsp[-1].minor);
5787 + yy_destructor(9,&yymsp[0].minor);
5790 +#line 282 "./configparser.y"
5792 yygotominor.yy40 = yymsp[-1].minor.yy40;
5793 yymsp[-1].minor.yy40 = NULL;
5795 -#line 995 "configparser.c"
5796 +#line 1016 "configparser.c"
5797 yy_destructor(8,&yymsp[-2].minor);
5798 yy_destructor(9,&yymsp[0].minor);
5801 -#line 275 "./configparser.y"
5803 +#line 287 "./configparser.y"
5805 if (buffer_is_empty(yymsp[0].minor.yy41->key) ||
5806 NULL == array_get_element(yymsp[-2].minor.yy40, yymsp[0].minor.yy41->key->ptr)) {
5807 @@ -1014,37 +1035,37 @@
5808 yygotominor.yy40 = yymsp[-2].minor.yy40;
5809 yymsp[-2].minor.yy40 = NULL;
5811 -#line 1017 "configparser.c"
5812 +#line 1038 "configparser.c"
5813 yy_destructor(10,&yymsp[-1].minor);
5816 -#line 292 "./configparser.y"
5818 +#line 304 "./configparser.y"
5820 yygotominor.yy40 = yymsp[-1].minor.yy40;
5821 yymsp[-1].minor.yy40 = NULL;
5823 -#line 1026 "configparser.c"
5824 +#line 1047 "configparser.c"
5825 yy_destructor(10,&yymsp[0].minor);
5828 -#line 297 "./configparser.y"
5830 +#line 309 "./configparser.y"
5832 yygotominor.yy40 = array_init();
5833 array_insert_unique(yygotominor.yy40, yymsp[0].minor.yy41);
5834 yymsp[0].minor.yy41 = NULL;
5836 -#line 1036 "configparser.c"
5837 +#line 1057 "configparser.c"
5840 -#line 303 "./configparser.y"
5842 +#line 315 "./configparser.y"
5844 yygotominor.yy41 = yymsp[0].minor.yy41;
5845 yymsp[0].minor.yy41 = NULL;
5847 -#line 1044 "configparser.c"
5848 +#line 1065 "configparser.c"
5851 -#line 307 "./configparser.y"
5853 +#line 319 "./configparser.y"
5855 buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5856 buffer_free(yymsp[-2].minor.yy43);
5857 @@ -1053,27 +1074,27 @@
5858 yygotominor.yy41 = yymsp[0].minor.yy41;
5859 yymsp[0].minor.yy41 = NULL;
5861 -#line 1056 "configparser.c"
5862 +#line 1077 "configparser.c"
5863 yy_destructor(11,&yymsp[-1].minor);
5866 - yy_destructor(1,&yymsp[0].minor);
5869 + yy_destructor(1,&yymsp[0].minor);
5872 -#line 319 "./configparser.y"
5875 +#line 331 "./configparser.y"
5878 dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
5880 configparser_push(ctx, dc, 0);
5882 -#line 1072 "configparser.c"
5883 +#line 1093 "configparser.c"
5884 yy_destructor(12,&yymsp[0].minor);
5887 -#line 326 "./configparser.y"
5889 +#line 338 "./configparser.y"
5893 @@ -1082,16 +1103,16 @@
5895 assert(cur && ctx->current);
5897 - yygotominor.yy0 = cur;
5898 + yygotominor.yy78 = cur;
5900 -#line 1087 "configparser.c"
5901 +#line 1108 "configparser.c"
5902 /* No destructor defined for globalstart */
5903 yy_destructor(13,&yymsp[-2].minor);
5904 /* No destructor defined for metalines */
5905 yy_destructor(14,&yymsp[0].minor);
5908 -#line 337 "./configparser.y"
5910 +#line 349 "./configparser.y"
5912 assert(yymsp[-3].minor.yy78->context_ndx < yymsp[0].minor.yy78->context_ndx);
5913 yymsp[0].minor.yy78->prev = yymsp[-3].minor.yy78;
5914 @@ -1100,20 +1121,20 @@
5915 yymsp[-3].minor.yy78 = NULL;
5916 yymsp[0].minor.yy78 = NULL;
5918 -#line 1103 "configparser.c"
5919 +#line 1124 "configparser.c"
5920 /* No destructor defined for eols */
5921 yy_destructor(15,&yymsp[-1].minor);
5924 -#line 346 "./configparser.y"
5926 +#line 358 "./configparser.y"
5928 yygotominor.yy78 = yymsp[0].minor.yy78;
5929 yymsp[0].minor.yy78 = NULL;
5931 -#line 1113 "configparser.c"
5932 +#line 1134 "configparser.c"
5935 -#line 351 "./configparser.y"
5937 +#line 363 "./configparser.y"
5941 @@ -1124,14 +1145,14 @@
5943 yygotominor.yy78 = cur;
5945 -#line 1127 "configparser.c"
5946 +#line 1148 "configparser.c"
5947 /* No destructor defined for context */
5948 yy_destructor(13,&yymsp[-2].minor);
5949 /* No destructor defined for metalines */
5950 yy_destructor(14,&yymsp[0].minor);
5953 -#line 362 "./configparser.y"
5955 +#line 374 "./configparser.y"
5958 buffer *b, *rvalue, *op;
5959 @@ -1183,6 +1204,7 @@
5960 { COMP_HTTP_USERAGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) },
5961 { COMP_HTTP_COOKIE, CONST_STR_LEN("HTTP[\"cookie\"]" ) },
5962 { COMP_HTTP_REMOTEIP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) },
5963 + { COMP_HTTP_QUERYSTRING, CONST_STR_LEN("HTTP[\"querystring\"]") },
5964 { COMP_UNSET, NULL, 0 },
5967 @@ -1266,45 +1288,45 @@
5968 yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5969 yymsp[0].minor.yy41 = NULL;
5971 -#line 1269 "configparser.c"
5972 +#line 1291 "configparser.c"
5973 yy_destructor(16,&yymsp[-6].minor);
5974 yy_destructor(18,&yymsp[-4].minor);
5975 yy_destructor(19,&yymsp[-2].minor);
5978 -#line 496 "./configparser.y"
5980 +#line 509 "./configparser.y"
5982 yygotominor.yy27 = CONFIG_COND_EQ;
5984 -#line 1279 "configparser.c"
5985 +#line 1301 "configparser.c"
5986 yy_destructor(20,&yymsp[0].minor);
5989 -#line 499 "./configparser.y"
5991 +#line 512 "./configparser.y"
5993 yygotominor.yy27 = CONFIG_COND_MATCH;
5995 -#line 1287 "configparser.c"
5996 +#line 1309 "configparser.c"
5997 yy_destructor(21,&yymsp[0].minor);
6000 -#line 502 "./configparser.y"
6002 +#line 515 "./configparser.y"
6004 yygotominor.yy27 = CONFIG_COND_NE;
6006 -#line 1295 "configparser.c"
6007 +#line 1317 "configparser.c"
6008 yy_destructor(22,&yymsp[0].minor);
6011 -#line 505 "./configparser.y"
6013 +#line 518 "./configparser.y"
6015 yygotominor.yy27 = CONFIG_COND_NOMATCH;
6017 -#line 1303 "configparser.c"
6018 +#line 1325 "configparser.c"
6019 yy_destructor(23,&yymsp[0].minor);
6022 -#line 509 "./configparser.y"
6024 +#line 522 "./configparser.y"
6026 yygotominor.yy43 = NULL;
6028 @@ -1321,10 +1343,10 @@
6029 yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
6030 yymsp[0].minor.yy41 = NULL;
6032 -#line 1324 "configparser.c"
6033 +#line 1346 "configparser.c"
6036 -#line 526 "./configparser.y"
6038 +#line 539 "./configparser.y"
6041 if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
6042 @@ -1334,11 +1356,11 @@
6043 yymsp[0].minor.yy43 = NULL;
6046 -#line 1337 "configparser.c"
6047 +#line 1359 "configparser.c"
6048 yy_destructor(24,&yymsp[-1].minor);
6051 -#line 536 "./configparser.y"
6053 +#line 549 "./configparser.y"
6056 if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
6057 @@ -1348,7 +1370,7 @@
6058 yymsp[0].minor.yy43 = NULL;
6061 -#line 1351 "configparser.c"
6062 +#line 1373 "configparser.c"
6063 yy_destructor(25,&yymsp[-1].minor);
6066 @@ -1378,11 +1400,11 @@
6067 while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
6068 /* Here code is inserted which will be executed whenever the
6070 -#line 125 "./configparser.y"
6071 +#line 107 "./configparser.y"
6075 -#line 1385 "configparser.c"
6076 +#line 1407 "configparser.c"
6077 configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
6080 @@ -1489,7 +1511,7 @@
6081 #ifdef YYERRORSYMBOL
6082 /* A syntax error has occurred.
6083 ** The response to an error depends upon whether or not the
6084 - ** grammar defines an error token "ERROR".
6085 + ** grammar defines an error token "ERROR".
6087 ** This is what we do if the grammar does define ERROR:
6089 --- ../lighttpd-1.4.11/src/configparser.y 2006-01-26 18:46:25.000000000 +0200
6090 +++ lighttpd-1.5.0/src/configparser.y 2006-09-07 00:57:05.000000000 +0300
6092 dc->parent = ctx->current;
6093 array_insert_unique(dc->parent->childs, (data_unset *)dc);
6095 - array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
6096 + buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
6100 static data_config *configparser_pop(config_t *ctx) {
6101 data_config *old = ctx->current;
6102 - ctx->current = (data_config *) array_pop(ctx->configs_stack);
6103 + ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
6107 /* return a copied variable */
6108 static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
6109 - if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
6112 - if (NULL != (env = getenv(key->ptr + 4))) {
6114 - ds = data_string_init();
6115 - buffer_append_string(ds->value, env);
6116 - return (data_unset *)ds;
6119 - fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
6130 - fprintf(stderr, "get var %s\n", key->ptr);
6131 + fprintf(stderr, "get var %s\n", key->ptr);
6133 - for (dc = ctx->current; dc; dc = dc->parent) {
6134 + for (dc = ctx->current; dc; dc = dc->parent) {
6136 - fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
6137 - array_print(dc->value, 0);
6138 + fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
6139 + array_print(dc->value, 0);
6141 - if (NULL != (du = array_get_element(dc->value, key->ptr))) {
6142 - return du->copy(du);
6144 + if (NULL != (du = array_get_element(dc->value, key->ptr))) {
6145 + return du->copy(du);
6147 - fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
6154 /* op1 is to be eat/return by this function, op1->key is not cared
6156 %type aelement {data_unset *}
6157 %type condline {data_config *}
6158 %type condlines {data_config *}
6159 +%type global {data_config *}
6160 %type aelements {array *}
6161 %type array {array *}
6162 %type key {buffer *}
6163 @@ -161,7 +144,12 @@
6165 varline ::= key(A) ASSIGN expression(B). {
6166 buffer_copy_string_buffer(B->key, A);
6167 - if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
6168 + if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
6169 + fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
6170 + ctx->current->context_ndx,
6171 + ctx->current->key->ptr, A->ptr);
6173 + } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
6174 array_insert_unique(ctx->current->value, B);
6177 @@ -180,7 +168,12 @@
6178 array *vars = ctx->current->value;
6181 - if (NULL != (du = array_get_element(vars, A->ptr))) {
6182 + if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
6183 + fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
6184 + ctx->current->context_ndx,
6185 + ctx->current->key->ptr, A->ptr);
6187 + } else if (NULL != (du = array_get_element(vars, A->ptr))) {
6188 /* exists in current block */
6189 du = configparser_merge_data(du, B);
6192 buffer_copy_string_buffer(du->key, A);
6193 array_replace(vars, du);
6196 } else if (NULL != (du = configparser_get_variable(ctx, A))) {
6197 du = configparser_merge_data(du, B);
6199 @@ -199,15 +193,13 @@
6200 buffer_copy_string_buffer(du->key, A);
6201 array_insert_unique(ctx->current->value, du);
6205 - fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n",
6206 - ctx->current->context_ndx,
6207 - ctx->current->key->ptr, A->ptr);
6209 + buffer_copy_string_buffer(B->key, A);
6210 + array_insert_unique(ctx->current->value, B);
6218 @@ -239,7 +231,24 @@
6221 value(A) ::= key(B). {
6222 - A = configparser_get_variable(ctx, B);
6223 + if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
6226 + if (NULL != (env = getenv(B->ptr + 4))) {
6228 + ds = data_string_init();
6229 + buffer_append_string(ds->value, env);
6230 + A = (data_unset *)ds;
6234 + fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
6237 + } else if (NULL == (A = configparser_get_variable(ctx, B))) {
6238 + fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
6242 /* make a dummy so it won't crash */
6243 A = (data_unset *)data_string_init();
6245 ((data_array *)(A))->value = B;
6248 +array(A) ::= LPARAN RPARAN. {
6251 array(A) ::= LPARAN aelements(B) RPARAN. {
6255 { COMP_HTTP_USERAGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) },
6256 { COMP_HTTP_COOKIE, CONST_STR_LEN("HTTP[\"cookie\"]" ) },
6257 { COMP_HTTP_REMOTEIP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) },
6258 + { COMP_HTTP_QUERYSTRING, CONST_STR_LEN("HTTP[\"querystring\"]") },
6259 { COMP_UNSET, NULL, 0 },
6262 --- ../lighttpd-1.4.11/src/connections-glue.c 2005-09-12 10:04:23.000000000 +0300
6263 +++ lighttpd-1.5.0/src/connections-glue.c 2006-09-07 00:57:05.000000000 +0300
6265 const char *connection_get_state(connection_state_t state) {
6267 case CON_STATE_CONNECT: return "connect";
6268 - case CON_STATE_READ: return "read";
6269 - case CON_STATE_READ_POST: return "readpost";
6270 - case CON_STATE_WRITE: return "write";
6271 - case CON_STATE_CLOSE: return "close";
6272 - case CON_STATE_ERROR: return "error";
6273 - case CON_STATE_HANDLE_REQUEST: return "handle-req";
6275 case CON_STATE_REQUEST_START: return "req-start";
6276 - case CON_STATE_REQUEST_END: return "req-end";
6277 - case CON_STATE_RESPONSE_START: return "resp-start";
6278 + case CON_STATE_READ_REQUEST_HEADER: return "read-header";
6279 + case CON_STATE_HANDLE_REQUEST_HEADER: return "handle-req";
6280 + case CON_STATE_READ_REQUEST_CONTENT: return "read-content";
6282 + case CON_STATE_HANDLE_RESPONSE_HEADER: return "resp-start";
6283 + case CON_STATE_WRITE_RESPONSE_HEADER: return "write-header";
6284 + case CON_STATE_WRITE_RESPONSE_CONTENT: return "write-content";
6285 case CON_STATE_RESPONSE_END: return "resp-end";
6286 - default: return "(unknown)";
6288 + case CON_STATE_CLOSE: return "close";
6289 + case CON_STATE_ERROR: return "error";
6290 + default: return "(unknown)";
6294 const char *connection_get_short_state(connection_state_t state) {
6296 case CON_STATE_CONNECT: return ".";
6297 - case CON_STATE_READ: return "r";
6298 - case CON_STATE_READ_POST: return "R";
6299 - case CON_STATE_WRITE: return "W";
6300 - case CON_STATE_CLOSE: return "C";
6301 - case CON_STATE_ERROR: return "E";
6302 - case CON_STATE_HANDLE_REQUEST: return "h";
6303 case CON_STATE_REQUEST_START: return "q";
6304 - case CON_STATE_REQUEST_END: return "Q";
6305 - case CON_STATE_RESPONSE_START: return "s";
6307 + case CON_STATE_READ_REQUEST_HEADER: return "r";
6308 + case CON_STATE_HANDLE_REQUEST_HEADER: return "h";
6309 + case CON_STATE_READ_REQUEST_CONTENT: return "R";
6311 + case CON_STATE_HANDLE_RESPONSE_HEADER: return "s";
6312 + case CON_STATE_WRITE_RESPONSE_HEADER: return "w";
6313 + case CON_STATE_WRITE_RESPONSE_CONTENT: return "W";
6314 case CON_STATE_RESPONSE_END: return "S";
6315 - default: return "x";
6317 + case CON_STATE_CLOSE: return "C";
6318 + case CON_STATE_ERROR: return "E";
6319 + default: return "x";
6323 int connection_set_state(server *srv, connection *con, connection_state_t state) {
6333 --- ../lighttpd-1.4.11/src/connections.c 2006-03-05 22:14:53.000000000 +0200
6334 +++ lighttpd-1.5.0/src/connections.c 2006-09-07 00:57:05.000000000 +0300
6339 -#include <unistd.h>
6344 #include "request.h"
6345 #include "response.h"
6346 #include "network.h"
6347 -#include "http_chunk.h"
6348 #include "stat_cache.h"
6349 #include "joblist.h"
6353 #include "inet_ntop_cache.h"
6354 +#include "configfile.h"
6355 +#include "http_req.h"
6358 -# include <openssl/ssl.h>
6359 -# include <openssl/err.h>
6360 +# include <openssl/ssl.h>
6361 +# include <openssl/err.h>
6364 #ifdef HAVE_SYS_FILIO_H
6368 #include "sys-socket.h"
6369 +#include "sys-files.h"
6376 static connection *connections_get_new_connection(server *srv) {
6377 connections *conns = srv->conns;
6381 if (conns->size == 0) {
6385 } else if (conns->size == conns->used) {
6387 conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size);
6390 for (i = conns->used; i < conns->size; i++) {
6391 conns->ptr[i] = connection_init(srv);
6395 connection_reset(srv, conns->ptr[conns->used]);
6397 - fprintf(stderr, "%s.%d: add: ", __FILE__, __LINE__);
6398 - for (i = 0; i < conns->used + 1; i++) {
6399 - fprintf(stderr, "%d ", conns->ptr[i]->fd);
6401 - fprintf(stderr, "\n");
6405 conns->ptr[conns->used]->ndx = conns->used;
6406 return conns->ptr[conns->used++];
6408 @@ -77,272 +71,127 @@
6410 connections *conns = srv->conns;
6414 if (con == NULL) return -1;
6417 if (-1 == con->ndx) return -1;
6423 /* not last element */
6426 if (i != conns->used - 1) {
6427 temp = conns->ptr[i];
6428 conns->ptr[i] = conns->ptr[conns->used - 1];
6429 conns->ptr[conns->used - 1] = temp;
6432 conns->ptr[i]->ndx = i;
6433 conns->ptr[conns->used - 1]->ndx = -1;
6442 - fprintf(stderr, "%s.%d: del: (%d)", __FILE__, __LINE__, conns->used);
6443 - for (i = 0; i < conns->used; i++) {
6444 - fprintf(stderr, "%d ", conns->ptr[i]->fd);
6446 - fprintf(stderr, "\n");
6452 int connection_close(server *srv, connection *con) {
6454 - server_socket *srv_sock = con->srv_socket;
6458 - if (srv_sock->is_ssl) {
6459 - if (con->ssl) SSL_free(con->ssl);
6461 + /* should be in iosocket_close() */
6463 + if (con->sock->ssl) {
6464 + switch (SSL_shutdown(con->sock->ssl)) {
6469 + /* wait for fd-event
6471 + * FIXME: wait for fdevent and call SSL_shutdown again
6477 + ERROR("SSL_shutdown failed: %s", ERR_error_string(ERR_get_error(), NULL));
6480 + SSL_free(con->sock->ssl);
6481 + con->sock->ssl = NULL;
6485 - fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
6486 - fdevent_unregister(srv->ev, con->fd);
6488 - if (closesocket(con->fd)) {
6489 - log_error_write(srv, __FILE__, __LINE__, "sds",
6490 - "(warning) close:", con->fd, strerror(errno));
6493 - if (close(con->fd)) {
6495 + fdevent_event_del(srv->ev, con->sock);
6496 + fdevent_unregister(srv->ev, con->sock);
6498 + if (closesocket(con->sock->fd)) {
6499 log_error_write(srv, __FILE__, __LINE__, "sds",
6500 - "(warning) close:", con->fd, strerror(errno));
6501 + "(warning) close:", con->sock->fd, strerror(errno));
6508 - log_error_write(srv, __FILE__, __LINE__, "sd",
6509 - "closed()", con->fd);
6513 connection_del(srv, con);
6514 connection_set_state(srv, con, CON_STATE_CONNECT);
6521 static void dump_packet(const unsigned char *data, size_t len) {
6525 if (len == 0) return;
6528 for (i = 0; i < len; i++) {
6529 if (i % 16 == 0) fprintf(stderr, " ");
6532 fprintf(stderr, "%02x ", data[i]);
6535 if ((i + 1) % 16 == 0) {
6536 fprintf(stderr, " ");
6537 for (j = 0; j <= i % 16; j++) {
6541 if (i-15+j >= len) break;
6547 fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6551 fprintf(stderr, "\n");
6556 if (len % 16 != 0) {
6557 for (j = i % 16; j < 16; j++) {
6558 fprintf(stderr, " ");
6562 fprintf(stderr, " ");
6563 for (j = i & ~0xf; j < len; j++) {
6568 fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6570 fprintf(stderr, "\n");
6575 -static int connection_handle_read(server *srv, connection *con) {
6580 - server_socket *srv_sock = con->srv_socket;
6583 - b = chunkqueue_get_append_buffer(con->read_queue);
6584 - buffer_prepare_copy(b, 4096);
6587 - if (srv_sock->is_ssl) {
6588 - len = SSL_read(con->ssl, b->ptr, b->size - 1);
6590 - if (ioctl(con->fd, FIONREAD, &toread)) {
6591 - log_error_write(srv, __FILE__, __LINE__, "sd",
6592 - "unexpected end-of-file:",
6596 - buffer_prepare_copy(b, toread);
6598 - len = read(con->fd, b->ptr, b->size - 1);
6600 -#elif defined(__WIN32)
6601 - len = recv(con->fd, b->ptr, b->size - 1, 0);
6603 - if (ioctl(con->fd, FIONREAD, &toread)) {
6604 - log_error_write(srv, __FILE__, __LINE__, "sd",
6605 - "unexpected end-of-file:",
6609 - buffer_prepare_copy(b, toread);
6611 - len = read(con->fd, b->ptr, b->size - 1);
6615 - con->is_readable = 0;
6618 - if (srv_sock->is_ssl) {
6621 - switch ((r = SSL_get_error(con->ssl, len))) {
6622 - case SSL_ERROR_WANT_READ:
6624 - case SSL_ERROR_SYSCALL:
6626 - * man SSL_get_error()
6628 - * SSL_ERROR_SYSCALL
6629 - * Some I/O error occurred. The OpenSSL error queue may contain more
6630 - * information on the error. If the error queue is empty (i.e.
6631 - * ERR_get_error() returns 0), ret can be used to find out more about
6632 - * the error: If ret == 0, an EOF was observed that violates the
6633 - * protocol. If ret == -1, the underlying BIO reported an I/O error
6634 - * (for socket I/O on Unix systems, consult errno for details).
6637 - while((ssl_err = ERR_get_error())) {
6638 - /* get all errors from the error-queue */
6639 - log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
6640 - r, ERR_error_string(ssl_err, NULL));
6645 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
6652 - case SSL_ERROR_ZERO_RETURN:
6653 - /* clean shutdown on the remote side */
6656 - /* FIXME: later */
6659 - /* fall thourgh */
6661 - while((ssl_err = ERR_get_error())) {
6662 - /* get all errors from the error-queue */
6663 - log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
6664 - r, ERR_error_string(ssl_err, NULL));
6669 - if (errno == EAGAIN) return 0;
6670 - if (errno == EINTR) {
6671 - /* we have been interrupted before we could read */
6672 - con->is_readable = 1;
6676 - if (errno != ECONNRESET) {
6677 - /* expected for keep-alive */
6678 - log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6682 - if (errno == EAGAIN) return 0;
6683 - if (errno == EINTR) {
6684 - /* we have been interrupted before we could read */
6685 - con->is_readable = 1;
6689 - if (errno != ECONNRESET) {
6690 - /* expected for keep-alive */
6691 - log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6694 - connection_set_state(srv, con, CON_STATE_ERROR);
6697 - } else if (len == 0) {
6698 - con->is_readable = 0;
6699 - /* the other end close the connection -> KEEP-ALIVE */
6704 - } else if ((size_t)len < b->size - 1) {
6705 - /* we got less then expected, wait for the next fd-event */
6707 - con->is_readable = 0;
6711 - b->ptr[b->used++] = '\0';
6713 - con->bytes_read += len;
6715 - dump_packet(b->ptr, len);
6720 +static int connection_handle_response_header(server *srv, connection *con) {
6723 -static int connection_handle_write_prepare(server *srv, connection *con) {
6724 if (con->mode == DIRECT) {
6726 switch(con->request.http_method) {
6727 case HTTP_METHOD_GET:
6728 case HTTP_METHOD_POST:
6729 case HTTP_METHOD_HEAD:
6731 case HTTP_METHOD_PUT:
6732 case HTTP_METHOD_MKCOL:
6733 case HTTP_METHOD_DELETE:
6734 @@ -350,21 +199,25 @@
6735 case HTTP_METHOD_MOVE:
6736 case HTTP_METHOD_PROPFIND:
6737 case HTTP_METHOD_PROPPATCH:
6738 + case HTTP_METHOD_LOCK:
6739 + case HTTP_METHOD_UNLOCK:
6741 case HTTP_METHOD_OPTIONS:
6743 * 400 is coming from the request-parser BEFORE uri.path is set
6744 - * 403 is from the response handler when noone else catched it
6746 + * 403 is from the response handler when noone else catched it
6749 if (con->uri.path->used &&
6750 con->uri.path->ptr[0] != '*') {
6751 response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
6753 + /* trash the content */
6754 + chunkqueue_reset(con->send);
6756 con->http_status = 200;
6757 - con->file_finished = 1;
6758 + con->send->is_closed = 1;
6760 - chunkqueue_reset(con->write_queue);
6764 @@ -381,55 +234,61 @@
6770 if (con->http_status == 0) {
6771 + TRACE("%s", "no status, setting 403");
6772 con->http_status = 403;
6776 switch(con->http_status) {
6777 case 400: /* class: header + custom body */
6795 if (con->mode != DIRECT) break;
6797 - con->file_finished = 0;
6800 + con->send->is_closed = 0;
6802 buffer_reset(con->physical.path);
6805 /* try to send static errorfile */
6806 if (!buffer_is_empty(con->conf.errorfile_prefix)) {
6807 stat_cache_entry *sce = NULL;
6810 buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix);
6811 buffer_append_string(con->physical.path, get_http_status_body_name(con->http_status));
6814 if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
6815 - con->file_finished = 1;
6817 - http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
6818 + con->send->is_closed = 1;
6820 + chunkqueue_append_file(con->send, con->physical.path, 0, sce->st.st_size);
6821 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
6825 - if (!con->file_finished) {
6827 + if (!con->send->is_closed) {
6831 buffer_reset(con->physical.path);
6833 - con->file_finished = 1;
6834 - b = chunkqueue_get_append_buffer(con->write_queue);
6837 + con->send->is_closed = 1;
6838 + b = chunkqueue_get_append_buffer(con->send);
6840 /* build default error-page */
6841 - buffer_copy_string(b,
6842 + buffer_copy_string(b,
6843 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
6844 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
6845 " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
6847 buffer_append_long(b, con->http_status);
6848 buffer_append_string(b, " - ");
6849 buffer_append_string(b, get_http_status_name(con->http_status));
6852 buffer_append_string(b,
6855 @@ -448,12 +307,12 @@
6856 buffer_append_long(b, con->http_status);
6857 buffer_append_string(b, " - ");
6858 buffer_append_string(b, get_http_status_name(con->http_status));
6860 - buffer_append_string(b,"</h1>\n"
6862 + buffer_append_string(b,"</h1>\n"
6868 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
6871 @@ -463,109 +322,69 @@
6877 case 206: /* write_queue is already prepared */
6878 - con->file_finished = 1;
6880 + con->send->is_closed = 1;
6883 case 205: /* class: header only */
6886 /* disable chunked encoding again as we have no body */
6887 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
6888 - chunkqueue_reset(con->write_queue);
6890 - con->file_finished = 1;
6891 + chunkqueue_reset(con->send);
6893 + con->send->is_closed = 1;
6899 - if (con->file_finished) {
6900 - /* we have all the content and chunked encoding is not used, set a content-length */
6902 - if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) &&
6903 - (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) {
6904 - buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->write_queue));
6907 + if (con->send->is_closed) {
6908 + /* we have all the content and chunked encoding is not used, set a content-length */
6910 + if ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0 &&
6911 + NULL == (cl = (data_string *)array_get_element(con->response.headers, "Content-Length"))) {
6912 + buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->send));
6914 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
6917 - /* disable keep-alive if size-info for the body is missing */
6918 - if ((con->parsed_response & HTTP_CONTENT_LENGTH) &&
6919 - ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) {
6920 - con->keep_alive = 0;
6923 - if (0 == (con->parsed_response & HTTP_CONNECTION)) {
6924 - /* (f)cgi did'nt send Connection: header
6928 - if (((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) &&
6929 - (con->parsed_response & HTTP_CONTENT_LENGTH) == 0) {
6930 - /* without content_length, no keep-alive */
6932 - con->keep_alive = 0;
6935 - /* a subrequest disable keep-alive although the client wanted it */
6936 - if (con->keep_alive && !con->response.keep_alive) {
6937 + if (NULL == (cl = (data_string *)array_get_element(con->response.headers, "Content-Length"))) {
6938 + /* we don't know the size of the content yet
6939 + * - either enable chunking
6940 + * - or disable keep-alive */
6942 + if (con->request.http_version == HTTP_VERSION_1_1) {
6943 + /* enable chunk-encoding */
6944 + con->response.transfer_encoding |= HTTP_TRANSFER_ENCODING_CHUNKED;
6946 con->keep_alive = 0;
6948 - /* FIXME: we have to drop the Connection: Header from the subrequest */
6954 if (con->request.http_method == HTTP_METHOD_HEAD) {
6955 - chunkqueue_reset(con->write_queue);
6956 + con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
6957 + chunkqueue_reset(con->send);
6959 + con->send->is_closed = 1;
6962 - http_response_write_header(srv, con);
6966 + http_response_write_header(srv, con, con->send_raw);
6968 -static int connection_handle_write(server *srv, connection *con) {
6969 - switch(network_write_chunkqueue(srv, con, con->write_queue)) {
6971 - if (con->file_finished) {
6972 - connection_set_state(srv, con, CON_STATE_RESPONSE_END);
6973 - joblist_append(srv, con);
6976 - case -1: /* error on our side */
6977 - log_error_write(srv, __FILE__, __LINE__, "sd",
6978 - "connection closed: write failed on fd", con->fd);
6979 - connection_set_state(srv, con, CON_STATE_ERROR);
6980 - joblist_append(srv, con);
6982 - case -2: /* remote close */
6983 - connection_set_state(srv, con, CON_STATE_ERROR);
6984 - joblist_append(srv, con);
6987 - con->is_writable = 0;
6989 - /* not finished yet -> WRITE */
6998 connection *connection_init(server *srv) {
7004 con = calloc(1, sizeof(*con));
7008 + con->sock = iosocket_init();
7010 - con->fde_ndx = -1;
7011 con->bytes_written = 0;
7012 con->bytes_read = 0;
7013 con->bytes_header = 0;
7014 @@ -573,91 +392,97 @@
7017 con->x = buffer_init();
7021 - CLEAN(request.request_line);
7022 CLEAN(request.request);
7023 CLEAN(request.pathinfo);
7025 + CLEAN(request.http_host);
7027 CLEAN(request.orig_uri);
7031 CLEAN(uri.authority);
7033 CLEAN(uri.path_raw);
7037 CLEAN(physical.doc_root);
7038 CLEAN(physical.path);
7039 CLEAN(physical.basedir);
7040 CLEAN(physical.rel_path);
7041 CLEAN(physical.etag);
7042 CLEAN(parse_request);
7047 CLEAN(error_handler);
7048 CLEAN(dst_addr_buf);
7052 - con->write_queue = chunkqueue_init();
7053 - con->read_queue = chunkqueue_init();
7054 - con->request_content_queue = chunkqueue_init();
7055 - chunkqueue_set_tempdirs(con->request_content_queue, srv->srvconf.upload_tempdirs);
7056 + con->send = chunkqueue_init();
7057 + con->recv = chunkqueue_init();
7059 + con->send_raw = chunkqueue_init();
7060 + con->recv_raw = chunkqueue_init();
7061 + chunkqueue_set_tempdirs(con->recv_raw, srv->srvconf.upload_tempdirs);
7063 con->request.headers = array_init();
7064 con->response.headers = array_init();
7065 con->environment = array_init();
7068 + con->http_req = http_request_init();
7070 /* init plugin specific connection structures */
7073 con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
7076 con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
7077 config_setup_connection(srv, con);
7083 void connections_free(server *srv) {
7084 connections *conns = srv->conns;
7089 for (i = 0; i < conns->size; i++) {
7090 connection *con = conns->ptr[i];
7093 connection_reset(srv, con);
7095 - chunkqueue_free(con->write_queue);
7096 - chunkqueue_free(con->read_queue);
7097 - chunkqueue_free(con->request_content_queue);
7098 + iosocket_free(con->sock);
7100 + chunkqueue_free(con->send);
7101 + chunkqueue_free(con->recv);
7102 + chunkqueue_free(con->send_raw);
7103 + chunkqueue_free(con->recv_raw);
7104 array_free(con->request.headers);
7105 array_free(con->response.headers);
7106 array_free(con->environment);
7109 buffer_free(con->x);
7113 - CLEAN(request.request_line);
7114 CLEAN(request.request);
7115 CLEAN(request.pathinfo);
7117 + CLEAN(request.http_host);
7119 CLEAN(request.orig_uri);
7123 CLEAN(uri.authority);
7125 CLEAN(uri.path_raw);
7129 CLEAN(physical.doc_root);
7130 CLEAN(physical.path);
7131 CLEAN(physical.basedir);
7132 CLEAN(physical.etag);
7133 CLEAN(physical.rel_path);
7134 CLEAN(parse_request);
7139 CLEAN(error_handler);
7140 @@ -665,97 +490,88 @@
7142 free(con->plugin_ctx);
7143 free(con->cond_cache);
7146 + http_request_free(con->http_req);
7156 int connection_reset(server *srv, connection *con) {
7160 plugins_call_connection_reset(srv, con);
7163 con->is_readable = 1;
7164 con->is_writable = 1;
7165 con->http_status = 0;
7166 - con->file_finished = 0;
7167 con->file_started = 0;
7168 con->got_response = 0;
7170 - con->parsed_response = 0;
7173 con->bytes_written = 0;
7174 con->bytes_written_cur_second = 0;
7175 con->bytes_read = 0;
7176 con->bytes_header = 0;
7177 con->loops_per_request = 0;
7180 con->request.http_method = HTTP_METHOD_UNSET;
7181 con->request.http_version = HTTP_VERSION_UNSET;
7183 - con->request.http_if_modified_since = NULL;
7184 - con->request.http_if_none_match = NULL;
7186 + con->request.content_length = -1;
7188 con->response.keep_alive = 0;
7189 con->response.content_length = -1;
7190 con->response.transfer_encoding = 0;
7197 if (con->x) buffer_reset(con->x);
7201 - CLEAN(request.request_line);
7202 CLEAN(request.pathinfo);
7203 CLEAN(request.request);
7205 + CLEAN(request.http_host);
7207 CLEAN(request.orig_uri);
7211 CLEAN(uri.authority);
7213 CLEAN(uri.path_raw);
7217 CLEAN(physical.doc_root);
7218 CLEAN(physical.path);
7219 CLEAN(physical.basedir);
7220 CLEAN(physical.rel_path);
7221 CLEAN(physical.etag);
7224 CLEAN(parse_request);
7229 CLEAN(error_handler);
7233 - if (con->x) con->x->used = 0;
7239 - con->request.x = NULL;
7242 - CLEAN(http_range);
7243 - CLEAN(http_content_type);
7244 + if (con->x) con->x->used = 0;
7247 - con->request.content_length = 0;
7250 array_reset(con->request.headers);
7251 array_reset(con->response.headers);
7252 array_reset(con->environment);
7254 - chunkqueue_reset(con->write_queue);
7255 - chunkqueue_reset(con->request_content_queue);
7257 - /* the plugins should cleanup themself */
7258 + chunkqueue_reset(con->send);
7259 + chunkqueue_reset(con->recv);
7260 + chunkqueue_reset(con->send_raw);
7262 + http_request_reset(con->http_req);
7264 + /* the plugins should cleanup themself */
7265 for (i = 0; i < srv->plugins.used; i++) {
7266 plugin *p = ((plugin **)(srv->plugins.ptr))[i];
7267 plugin_data *pd = p->data;
7268 @@ -768,455 +584,270 @@
7270 con->plugin_ctx[pd->id] = NULL;
7273 -#if COND_RESULT_UNSET
7274 - for (i = srv->config_context->used - 1; i >= 0; i --) {
7275 - con->cond_cache[i].result = COND_RESULT_UNSET;
7276 - con->cond_cache[i].patterncount = 0;
7279 - memset(con->cond_cache, 0, sizeof(cond_cache_t) * srv->config_context->used);
7283 + config_cond_cache_reset(srv, con);
7285 con->header_len = 0;
7286 con->in_error_handler = 0;
7289 config_setup_connection(srv, con);
7297 - * search for \r\n\r\n
7299 - * this is a special 32bit version which is using a sliding window for
7300 - * the comparisions
7307 - * cmpbuf: abcd != cdef
7308 - * cmpbuf: bcde != cdef
7309 - * cmpbuf: cdef == cdef -> return &c
7311 - * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to
7312 - * maintain cmpbuf and rnrn
7316 -char *buffer_search_rnrn(buffer *b) {
7317 - uint32_t cmpbuf, rnrn;
7321 - if (b->used < 4) return NULL;
7323 - rnrn = ('\r' << 24) | ('\n' << 16) |
7324 - ('\r' << 8) | ('\n' << 0);
7326 - cmpbuf = (b->ptr[0] << 24) | (b->ptr[1] << 16) |
7327 - (b->ptr[2] << 8) | (b->ptr[3] << 0);
7330 - for (i = 0; i < b->used - 4; i++) {
7331 - if (cmpbuf == rnrn) return cp - 4;
7333 - cmpbuf = (cmpbuf << 8 | *(cp++)) & 0xffffffff;
7339 * handle all header and content read
7341 * we get called by the state-engine and by the fdevent-handler
7343 -int connection_handle_read_state(server *srv, connection *con) {
7344 - int ostate = con->state;
7345 - char *h_term = NULL;
7347 - chunkqueue *cq = con->read_queue;
7348 - chunkqueue *dst_cq = con->request_content_queue;
7350 - if (con->is_readable) {
7351 - con->read_idle_ts = srv->cur_ts;
7353 - switch(connection_handle_read(srv, con)) {
7357 - /* remote side closed the connection
7358 - * if we still have content, handle it, if not leave here */
7359 +handler_t connection_handle_read_request_header(server *srv, connection *con) {
7360 + /* let's see if we need more data later */
7361 + fdevent_event_del(srv->ev, con->sock);
7363 + con->read_idle_ts = srv->cur_ts; /* start a read-call() */
7365 + /* read from the network */
7366 + switch (network_read(srv, con, con->sock, con->recv_raw)) {
7367 + case NETWORK_STATUS_SUCCESS:
7368 + /* we read everything from the socket, do we have a full header ? */
7370 - if (cq->first == cq->last &&
7371 - cq->first->mem->used == 0) {
7373 + case NETWORK_STATUS_WAIT_FOR_EVENT:
7374 + fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
7375 + return HANDLER_WAIT_FOR_EVENT;
7376 + case NETWORK_STATUS_CONNECTION_CLOSE:
7377 + /* the connection went away before we got something back */
7378 + connection_set_state(srv, con, CON_STATE_CLOSE);
7380 - /* conn-closed, leave here */
7381 - connection_set_state(srv, con, CON_STATE_ERROR);
7386 + return HANDLER_GO_ON;
7388 + ERROR("++ %s", "oops, something went wrong while reading");
7389 + return HANDLER_ERROR;
7392 - /* the last chunk might be empty */
7393 - for (c = cq->first; c;) {
7394 - if (cq->first == c && c->mem->used == 0) {
7395 - /* the first node is empty */
7396 - /* ... and it is empty, move it to unused */
7398 - cq->first = c->next;
7399 - if (cq->first == NULL) cq->last = NULL;
7401 - c->next = cq->unused;
7403 - cq->unused_chunks++;
7406 - } else if (c->next && c->next->mem->used == 0) {
7408 - /* next node is the last one */
7409 - /* ... and it is empty, move it to unused */
7412 - c->next = fc->next;
7414 - fc->next = cq->unused;
7416 - cq->unused_chunks++;
7418 - /* the last node was empty */
7419 - if (c->next == NULL) {
7427 + switch (http_request_parse_cq(con->recv_raw, con->http_req)) {
7429 + con->http_status = 400; /* the header is broken */
7431 + chunkqueue_remove_finished_chunks(con->recv_raw);
7433 + return HANDLER_FINISHED;
7434 + case PARSE_NEED_MORE:
7435 + /* we need more */
7436 + fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
7438 + return HANDLER_WAIT_FOR_EVENT;
7439 + case PARSE_SUCCESS:
7440 + chunkqueue_remove_finished_chunks(con->recv_raw);
7443 + chunkqueue_remove_finished_chunks(con->recv_raw);
7444 + TRACE("%s", "(error)");
7445 + return HANDLER_ERROR;
7448 + return HANDLER_GO_ON;
7451 +/* decode the HTTP/1.1 chunk encoding */
7453 +handler_t connection_handle_read_request_content(server *srv, connection *con) {
7454 + /* read data from the socket and push it to the backend */
7456 + chunkqueue *in = con->recv_raw;
7457 + chunkqueue *out = con->recv; /* the pure content */
7460 - /* nothing to handle */
7461 - if (cq->first == NULL) return 0;
7462 + /* let's see if we need more data later */
7463 + fdevent_event_del(srv->ev, con->sock);
7465 + con->read_idle_ts = srv->cur_ts; /* start a read-call() */
7467 + if (con->request.content_length == -1) return HANDLER_GO_ON;
7469 + /* if the content was short enough, it might be read already */
7471 + chunkqueue_length(in) - in->first->offset > 0) {
7474 - case CON_STATE_READ:
7475 - /* prepare con->request.request */
7478 + * looks like the request-header also had some content for us
7481 - /* check if we need the full package */
7482 - if (con->request.request->used == 0) {
7485 - b.ptr = c->mem->ptr + c->offset;
7486 - b.used = c->mem->used - c->offset;
7488 - if (NULL != (h_term = buffer_search_rnrn(&b))) {
7490 - * - copy everything incl. the terminator to request.request
7493 - buffer_copy_string_len(con->request.request,
7495 - h_term - b.ptr + 4);
7497 - /* the buffer has been read up to the terminator */
7498 - c->offset += h_term - b.ptr + 4;
7500 - /* not found, copy everything */
7501 - buffer_copy_string_len(con->request.request, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
7502 - c->offset = c->mem->used - 1;
7505 - /* have to take care of overlapping header terminators */
7507 - size_t l = con->request.request->used - 2;
7508 - char *s = con->request.request->ptr;
7511 - b.ptr = c->mem->ptr + c->offset;
7512 - b.used = c->mem->used - c->offset;
7514 - if (con->request.request->used - 1 > 3 &&
7515 - c->mem->used > 1 &&
7519 - c->mem->ptr[0] == '\n') {
7520 - buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 1);
7523 - h_term = con->request.request->ptr;
7524 - } else if (con->request.request->used - 1 > 2 &&
7525 - c->mem->used > 2 &&
7528 - c->mem->ptr[0] == '\r' &&
7529 - c->mem->ptr[1] == '\n') {
7530 - buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 2);
7533 - h_term = con->request.request->ptr;
7534 - } else if (con->request.request->used - 1 > 1 &&
7535 - c->mem->used > 3 &&
7537 - c->mem->ptr[0] == '\n' &&
7538 - c->mem->ptr[1] == '\r' &&
7539 - c->mem->ptr[2] == '\n') {
7540 - buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 3);
7543 - h_term = con->request.request->ptr;
7544 - } else if (NULL != (h_term = buffer_search_string_len(&b, "\r\n\r\n", 4))) {
7546 - * - copy everything incl. the terminator to request.request
7549 - buffer_append_string_len(con->request.request,
7550 - c->mem->ptr + c->offset,
7551 - c->offset + h_term - b.ptr + 4);
7553 - /* the buffer has been read up to the terminator */
7554 - c->offset += h_term - b.ptr + 4;
7556 - /* not found, copy everything */
7557 - buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
7558 - c->offset = c->mem->used - 1;
7561 + /* read from the network */
7562 + switch (network_read(srv, con, con->sock, in)) {
7563 + case NETWORK_STATUS_SUCCESS:
7564 + /* we have data */
7566 + case NETWORK_STATUS_WAIT_FOR_EVENT:
7567 + fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
7568 + TRACE("%s", "content-read: wait-for-event");
7569 + return HANDLER_WAIT_FOR_EVENT;
7570 + case NETWORK_STATUS_CONNECTION_CLOSE:
7571 + /* the connection went away before we got something back */
7572 + connection_set_state(srv, con, CON_STATE_CLOSE);
7574 + return HANDLER_GO_ON;
7576 + ERROR("++ %s", "oops, something went wrong while reading");
7577 + return HANDLER_ERROR;
7581 - /* con->request.request is setup up */
7583 - connection_set_state(srv, con, CON_STATE_REQUEST_END);
7584 - } else if (con->request.request->used > 64 * 1024) {
7585 - log_error_write(srv, __FILE__, __LINE__, "s", "oversized request-header -> sending Status 414");
7586 + /* how much data do we want to extract ? */
7587 + for (c = in->first; c && (out->bytes_in != con->request.content_length); c = c->next) {
7588 + off_t weWant, weHave, toRead;
7590 - con->http_status = 414; /* Request-URI too large */
7591 - con->keep_alive = 0;
7592 - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7595 - case CON_STATE_READ_POST:
7596 - for (c = cq->first; c && (dst_cq->bytes_in != (off_t)con->request.content_length); c = c->next) {
7597 - off_t weWant, weHave, toRead;
7599 - weWant = con->request.content_length - dst_cq->bytes_in;
7601 - assert(c->mem->used);
7603 - weHave = c->mem->used - c->offset - 1;
7605 - toRead = weHave > weWant ? weWant : weHave;
7607 - /* the new way, copy everything into a chunkqueue whcih might use tempfiles */
7608 - if (con->request.content_length > 64 * 1024) {
7609 - chunk *dst_c = NULL;
7610 - /* copy everything to max 1Mb sized tempfiles */
7613 - * if the last chunk is
7614 - * - smaller than 1Mb (size < 1Mb)
7615 - * - not read yet (offset == 0)
7618 - * -> create a new chunk
7622 - if (dst_cq->last &&
7623 - dst_cq->last->type == FILE_CHUNK &&
7624 - dst_cq->last->file.is_temp &&
7625 - dst_cq->last->offset == 0) {
7626 - /* ok, take the last chunk for our job */
7628 - if (dst_cq->last->file.length < 1 * 1024 * 1024) {
7629 - dst_c = dst_cq->last;
7631 - if (dst_c->file.fd == -1) {
7632 - /* this should not happen as we cache the fd, but you never know */
7633 - dst_c->file.fd = open(dst_c->file.name->ptr, O_WRONLY | O_APPEND);
7636 - /* the chunk is too large now, close it */
7637 - dst_c = dst_cq->last;
7638 + weWant = con->request.content_length - out->bytes_in;
7640 + if (c->mem->used == 0) continue;
7642 - if (dst_c->file.fd != -1) {
7643 - close(dst_c->file.fd);
7644 - dst_c->file.fd = -1;
7646 - dst_c = chunkqueue_get_append_tempfile(dst_cq);
7647 + weHave = c->mem->used - c->offset - 1;
7649 + toRead = weHave > weWant ? weWant : weHave;
7651 + /* the new way, copy everything into a chunkqueue whcih might use tempfiles */
7652 + if (con->request.content_length > 64 * 1024) {
7653 + chunk *dst_c = NULL;
7654 + /* copy everything to max 1Mb sized tempfiles */
7657 + * if the last chunk is
7658 + * - smaller than 1Mb (size < 1Mb)
7659 + * - not read yet (offset == 0)
7662 + * -> create a new chunk
7667 + out->last->type == FILE_CHUNK &&
7668 + out->last->file.is_temp &&
7669 + out->last->offset == 0) {
7670 + /* ok, take the last chunk for our job */
7672 + if (out->last->file.length < 1 * 1024 * 1024) {
7673 + dst_c = out->last;
7675 + if (dst_c->file.fd == -1) {
7676 + /* this should not happen as we cache the fd, but you never know */
7677 + dst_c->file.fd = open(dst_c->file.name->ptr, O_WRONLY | O_APPEND);
7680 - dst_c = chunkqueue_get_append_tempfile(dst_cq);
7681 + /* the chunk is too large now, close it */
7682 + dst_c = out->last;
7684 + if (dst_c->file.fd != -1) {
7685 + close(dst_c->file.fd);
7686 + dst_c->file.fd = -1;
7688 + dst_c = chunkqueue_get_append_tempfile(out);
7691 + dst_c = chunkqueue_get_append_tempfile(out);
7694 + /* we have a chunk, let's write to it */
7696 - /* we have a chunk, let's write to it */
7697 + if (dst_c->file.fd == -1) {
7698 + /* we don't have file to write to,
7699 + * EACCES might be one reason.
7701 + * Instead of sending 500 we send 413 and say the request is too large
7704 - if (dst_c->file.fd == -1) {
7705 - /* we don't have file to write to,
7706 - * EACCES might be one reason.
7708 - * Instead of sending 500 we send 413 and say the request is too large
7711 - log_error_write(srv, __FILE__, __LINE__, "sbs",
7712 - "denying upload as opening to temp-file for upload failed:",
7713 - dst_c->file.name, strerror(errno));
7715 - con->http_status = 413; /* Request-Entity too large */
7716 - con->keep_alive = 0;
7717 - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7718 + log_error_write(srv, __FILE__, __LINE__, "sbs",
7719 + "denying upload as opening to temp-file for upload failed:",
7720 + dst_c->file.name, strerror(errno));
7724 + con->http_status = 413; /* Request-Entity too large */
7725 + con->keep_alive = 0;
7726 + return HANDLER_FINISHED;
7729 - if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) {
7730 - /* write failed for some reason ... disk full ? */
7731 - log_error_write(srv, __FILE__, __LINE__, "sbs",
7732 - "denying upload as writing to file failed:",
7733 - dst_c->file.name, strerror(errno));
7735 - con->http_status = 413; /* Request-Entity too large */
7736 - con->keep_alive = 0;
7737 - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7739 - close(dst_c->file.fd);
7740 - dst_c->file.fd = -1;
7741 + if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) {
7742 + /* write failed for some reason ... disk full ? */
7743 + log_error_write(srv, __FILE__, __LINE__, "sbs",
7744 + "denying upload as writing to file failed:",
7745 + dst_c->file.name, strerror(errno));
7749 + con->http_status = 413; /* Request-Entity too large */
7750 + con->keep_alive = 0;
7752 - dst_c->file.length += toRead;
7754 - if (dst_cq->bytes_in + toRead == (off_t)con->request.content_length) {
7755 - /* we read everything, close the chunk */
7756 - close(dst_c->file.fd);
7757 - dst_c->file.fd = -1;
7761 + close(dst_c->file.fd);
7762 + dst_c->file.fd = -1;
7764 - b = chunkqueue_get_append_buffer(dst_cq);
7765 - buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead);
7766 + return HANDLER_FINISHED;
7769 - c->offset += toRead;
7770 - dst_cq->bytes_in += toRead;
7773 - /* Content is ready */
7774 - if (dst_cq->bytes_in == (off_t)con->request.content_length) {
7775 - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7776 + dst_c->file.length += toRead;
7778 + if (out->bytes_in + toRead == con->request.content_length) {
7779 + /* we read everything, close the chunk */
7780 + close(dst_c->file.fd);
7781 + dst_c->file.fd = -1;
7786 + b = chunkqueue_get_append_buffer(out);
7787 + buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead);
7792 + c->offset += toRead;
7794 + out->bytes_in += toRead;
7795 + in->bytes_out += toRead;
7798 - chunkqueue_remove_finished_chunks(cq);
7799 + if (out->bytes_in < con->request.content_length) {
7800 + /* we have to read more content */
7801 + fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
7805 + return HANDLER_GO_ON;
7808 handler_t connection_handle_fdevent(void *s, void *context, int revents) {
7809 server *srv = (server *)s;
7810 connection *con = context;
7812 - joblist_append(srv, con);
7815 if (revents & FDEVENT_IN) {
7816 - con->is_readable = 1;
7818 - log_error_write(srv, __FILE__, __LINE__, "sd", "read-wait - done", con->fd);
7820 + switch (con->state) {
7821 + case CON_STATE_READ_REQUEST_HEADER:
7822 + case CON_STATE_READ_REQUEST_CONTENT:
7823 + joblist_append(srv, con);
7825 + case CON_STATE_CLOSE:
7828 + ERROR("%s", "I thought only READ_REQUEST_* need fdevent-in");
7833 if (revents & FDEVENT_OUT) {
7834 - con->is_writable = 1;
7835 - /* we don't need the event twice */
7836 + switch (con->state) {
7837 + case CON_STATE_WRITE_RESPONSE_HEADER:
7838 + case CON_STATE_WRITE_RESPONSE_CONTENT:
7839 + joblist_append(srv, con);
7842 + ERROR("%s", "I thought only WRITE_RESPONSE_* need fdevent-out");
7849 if (revents & ~(FDEVENT_IN | FDEVENT_OUT)) {
7850 /* looks like an error */
7852 - /* FIXME: revents = 0x19 still means that we should read from the queue */
7853 - if (revents & FDEVENT_HUP) {
7854 - if (con->state == CON_STATE_CLOSE) {
7855 - con->close_timeout_ts = 0;
7857 - /* sigio reports the wrong event here
7859 - * there was no HUP at all
7861 -#ifdef USE_LINUX_SIGIO
7862 - if (srv->ev->in_sigio == 1) {
7863 - log_error_write(srv, __FILE__, __LINE__, "sd",
7864 - "connection closed: poll() -> HUP", con->fd);
7866 - connection_set_state(srv, con, CON_STATE_ERROR);
7869 - connection_set_state(srv, con, CON_STATE_ERROR);
7873 - } else if (revents & FDEVENT_ERR) {
7874 -#ifndef USE_LINUX_SIGIO
7875 - log_error_write(srv, __FILE__, __LINE__, "sd",
7876 - "connection closed: poll() -> ERR", con->fd);
7878 - connection_set_state(srv, con, CON_STATE_ERROR);
7880 - log_error_write(srv, __FILE__, __LINE__, "sd",
7881 - "connection closed: poll() -> ???", revents);
7885 - if (con->state == CON_STATE_READ ||
7886 - con->state == CON_STATE_READ_POST) {
7887 - connection_handle_read_state(srv, con);
7890 - if (con->state == CON_STATE_WRITE &&
7891 - !chunkqueue_is_empty(con->write_queue) &&
7892 - con->is_writable) {
7894 - if (-1 == connection_handle_write(srv, con)) {
7895 - connection_set_state(srv, con, CON_STATE_ERROR);
7897 - log_error_write(srv, __FILE__, __LINE__, "ds",
7899 - "handle write failed.");
7900 - } else if (con->state == CON_STATE_WRITE) {
7901 - con->write_request_ts = srv->cur_ts;
7905 - if (con->state == CON_STATE_CLOSE) {
7906 - /* flush the read buffers */
7909 - if (ioctl(con->fd, FIONREAD, &b)) {
7910 - log_error_write(srv, __FILE__, __LINE__, "ss",
7911 - "ioctl() failed", strerror(errno));
7916 - log_error_write(srv, __FILE__, __LINE__, "sdd",
7917 - "CLOSE-read()", con->fd, b);
7920 - read(con->fd, buf, sizeof(buf));
7922 - /* nothing to read */
7924 - con->close_timeout_ts = 0;
7927 + connection_set_state(srv, con, CON_STATE_ERROR);
7928 + joblist_append(srv, con);
7933 return HANDLER_FINISHED;
7936 @@ -1229,63 +860,78 @@
7939 /* accept it and register the fd */
7942 cnt_len = sizeof(cnt_addr);
7944 - if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7945 - if ((errno != EAGAIN) &&
7946 - (errno != EINTR)) {
7947 - log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno);
7948 + if (-1 == (cnt = accept(srv_socket->sock->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7950 + errno = WSAGetLastError();
7954 +#if EWOULDBLOCK != EAGAIN
7958 + /* we were stopped _before_ we had a connection */
7959 + case ECONNABORTED: /* this is a FreeBSD thingy */
7960 + /* we were stopped _after_ we had a connection */
7963 + ERROR("accept failed on fd=%d with error: (%d) %s", srv_socket->sock->fd, errno, strerror(errno));
7974 /* ok, we have the connection, register it */
7976 log_error_write(srv, __FILE__, __LINE__, "sd",
7982 con = connections_get_new_connection(srv);
7985 - con->fde_ndx = -1;
7987 + con->sock->fd = cnt;
7988 + con->sock->fde_ndx = -1;
7990 gettimeofday(&(con->start_tv), NULL);
7992 - fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con);
7995 + fdevent_register(srv->ev, con->sock, connection_handle_fdevent, con);
7997 connection_set_state(srv, con, CON_STATE_REQUEST_START);
8000 con->connection_start = srv->cur_ts;
8001 con->dst_addr = cnt_addr;
8002 buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
8003 con->srv_socket = srv_socket;
8005 - if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) {
8007 + if (-1 == (fdevent_fcntl_set(srv->ev, con->sock))) {
8008 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
8009 + connection_close(srv, con);
8014 /* connect FD to SSL */
8015 if (srv_socket->is_ssl) {
8016 - if (NULL == (con->ssl = SSL_new(srv_socket->ssl_ctx))) {
8017 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
8018 + if (NULL == (con->sock->ssl = SSL_new(srv_socket->ssl_ctx))) {
8019 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
8020 ERR_error_string(ERR_get_error(), NULL));
8022 + connection_close(srv, con);
8026 - SSL_set_accept_state(con->ssl);
8028 + SSL_set_accept_state(con->sock->ssl);
8031 - if (1 != (SSL_set_fd(con->ssl, cnt))) {
8032 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
8034 + if (1 != (SSL_set_fd(con->sock->ssl, cnt))) {
8035 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
8036 ERR_error_string(ERR_get_error(), NULL));
8037 + connection_close(srv, con);
8041 @@ -1294,182 +940,452 @@
8045 +static int http_chunk_append_len(chunkqueue *cq, size_t len) {
8046 + size_t i, olen = len, j;
8049 + b = buffer_init();
8052 + buffer_copy_string(b, "0");
8054 + for (i = 0; i < 8 && len; i++) {
8058 + /* i is the number of hex digits we have */
8059 + buffer_prepare_copy(b, i + 1);
8061 + for (j = i-1, len = olen; j+1 > 0; j--) {
8062 + b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
8066 + b->ptr[b->used++] = '\0';
8069 + buffer_append_string(b, "\r\n");
8070 + chunkqueue_append_buffer(cq, b);
8079 + * apply chunk encoding if necessary
8081 +int http_stream_encoder(server *srv, connection *con, chunkqueue *in, chunkqueue *out) {
8087 + is_chunked = (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED);
8090 + for (c = in->first; c; c = c->next) {
8091 + switch (c->type) {
8093 + if (c->mem->used == 0) continue;
8095 + http_chunk_append_len(out, c->mem->used - 1);
8096 + chunkqueue_append_buffer(out, c->mem);
8097 + c->offset = c->mem->used - 1;
8100 + if (c->file.length == 0) continue;
8102 + http_chunk_append_len(out, c->file.length);
8103 + chunkqueue_append_file(out, c->file.name, c->file.start, c->file.length);
8105 + c->offset = c->file.length;
8108 + chunkqueue_append_mem(out, "\r\n", 2 + 1);
8110 + if (in->is_closed) http_chunk_append_len(out, 0);
8112 + for (c = in->first; c; c = c->next) {
8113 + switch (c->type) {
8115 + if (c->mem->used == 0) continue;
8117 + chunkqueue_append_buffer(out, c->mem);
8118 + c->offset = c->mem->used - 1;
8121 + if (c->file.length == 0) continue;
8123 + chunkqueue_append_file(out, c->file.name, c->file.start, c->file.length);
8125 + c->offset = c->file.length;
8131 + chunkqueue_remove_finished_chunks(in);
8136 int connection_state_machine(server *srv, connection *con) {
8139 server_socket *srv_sock = con->srv_socket;
8143 if (srv->srvconf.log_state_handling) {
8144 - log_error_write(srv, __FILE__, __LINE__, "sds",
8147 + log_error_write(srv, __FILE__, __LINE__, "sds",
8150 connection_get_state(con->state));
8154 size_t ostate = con->state;
8158 switch (con->state) {
8159 - case CON_STATE_REQUEST_START: /* transient */
8160 + case CON_STATE_CONNECT:
8161 if (srv->srvconf.log_state_handling) {
8162 - log_error_write(srv, __FILE__, __LINE__, "sds",
8163 - "state for fd", con->fd, connection_get_state(con->state));
8164 + log_error_write(srv, __FILE__, __LINE__, "sds",
8165 + "state for fd", con->sock->fd, connection_get_state(con->state));
8168 - con->request_start = srv->cur_ts;
8169 - con->read_idle_ts = srv->cur_ts;
8171 - con->request_count++;
8172 - con->loops_per_request = 0;
8174 - connection_set_state(srv, con, CON_STATE_READ);
8177 + chunkqueue_reset(con->recv_raw); /* this is a new connection, trash the pipeline */
8179 + con->request_count = 0;
8182 - case CON_STATE_REQUEST_END: /* transient */
8183 + case CON_STATE_REQUEST_START:
8184 + /* init the request handling */
8185 if (srv->srvconf.log_state_handling) {
8186 - log_error_write(srv, __FILE__, __LINE__, "sds",
8187 - "state for fd", con->fd, connection_get_state(con->state));
8188 + log_error_write(srv, __FILE__, __LINE__, "sds",
8189 + "state for fd", con->sock->fd, connection_get_state(con->state));
8192 - if (http_request_parse(srv, con)) {
8193 - /* we have to read some data from the POST request */
8195 - connection_set_state(srv, con, CON_STATE_READ_POST);
8197 + con->request_start = srv->cur_ts; /* start of the request */
8198 + con->read_idle_ts = srv->cur_ts; /* start a read-call() */
8200 + con->request_count++; /* max-keepalive requests */
8201 + con->loops_per_request = 0; /* infinite loops */
8203 + /* if the content was short enough, it might have a header already in the pipe */
8204 + if (con->recv_raw->first &&
8205 + chunkqueue_length(con->recv_raw) - con->recv_raw->first->offset > 0) {
8208 + switch (http_request_parse_cq(con->recv_raw, con->http_req)) {
8210 + con->http_status = 400; /* the header is broken */
8212 + chunkqueue_remove_finished_chunks(con->recv_raw);
8214 + connection_set_state(srv, con, CON_STATE_HANDLE_RESPONSE_HEADER);
8216 + case PARSE_NEED_MORE:
8217 + /* the read() call is on the way */
8218 + connection_set_state(srv, con, CON_STATE_READ_REQUEST_HEADER);
8220 + case PARSE_SUCCESS:
8221 + /* pipelining worked, validate the header */
8222 + chunkqueue_remove_finished_chunks(con->recv_raw);
8224 + connection_set_state(srv, con, CON_STATE_VALIDATE_REQUEST_HEADER);
8227 + chunkqueue_remove_finished_chunks(con->recv_raw);
8228 + TRACE("%s", "(error)");
8229 + return HANDLER_ERROR;
8232 + connection_set_state(srv, con, CON_STATE_READ_REQUEST_HEADER);
8236 + case CON_STATE_READ_REQUEST_HEADER:
8237 + /* read us much data as needed into the recv_raw-cq for a valid header */
8238 + if (srv->srvconf.log_state_handling) {
8239 + TRACE("state for fd=%d: %s", con->sock->fd, connection_get_state(con->state));
8242 + switch (connection_handle_read_request_header(srv, con)) {
8243 + case HANDLER_GO_ON:
8244 + connection_set_state(srv, con, CON_STATE_VALIDATE_REQUEST_HEADER);
8246 + case HANDLER_FINISHED:
8247 + connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE_HEADER);
8249 + case HANDLER_WAIT_FOR_EVENT:
8250 + return HANDLER_WAIT_FOR_EVENT;
8251 + case HANDLER_ERROR:
8252 + TRACE("%s", "(error)");
8253 + connection_set_state(srv, con, CON_STATE_ERROR);
8256 + TRACE("%s", "(error)");
8257 + connection_set_state(srv, con, CON_STATE_ERROR);
8261 - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
8264 - case CON_STATE_HANDLE_REQUEST:
8266 - * the request is parsed
8268 - * decided what to do with the request
8274 + case CON_STATE_VALIDATE_REQUEST_HEADER:
8275 + /* we have the full header, parse it */
8277 + http_request_parse(srv, con, con->http_req);
8279 + if (con->http_status != 0) {
8280 + con->keep_alive = 0;
8281 + con->send->is_closed = 1; /* there is no content */
8283 + connection_set_state(srv, con, CON_STATE_HANDLE_RESPONSE_HEADER);
8284 + } else if (array_get_element(con->request.headers, "Expect")) {
8286 + con->http_status = 100;
8287 + con->send->is_closed = 1;
8288 + TRACE("%s", "setting status 100");
8290 + connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE_HEADER);
8292 + /* parsing the request went fine
8293 + * let's find a handler for this request */
8294 + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST_HEADER);
8298 + case CON_STATE_HANDLE_REQUEST_HEADER:
8299 + /* the request header is parsed,
8300 + * find someone who wants to handle this request */
8302 if (srv->srvconf.log_state_handling) {
8303 - log_error_write(srv, __FILE__, __LINE__, "sds",
8304 - "state for fd", con->fd, connection_get_state(con->state));
8305 + log_error_write(srv, __FILE__, __LINE__, "sds",
8306 + "state for fd", con->sock->fd, connection_get_state(con->state));
8309 - switch (r = http_response_prepare(srv, con)) {
8311 + switch (r = handle_get_backend(srv, con)) {
8312 + case HANDLER_GO_ON:
8313 case HANDLER_FINISHED:
8314 - if (con->http_status == 404 ||
8315 - con->http_status == 403) {
8316 - /* 404 error-handler */
8318 - if (con->in_error_handler == 0 &&
8319 - (!buffer_is_empty(con->conf.error_handler) ||
8320 - !buffer_is_empty(con->error_handler))) {
8321 - /* call error-handler */
8323 - con->error_handler_saved_status = con->http_status;
8324 - con->http_status = 0;
8326 - if (buffer_is_empty(con->error_handler)) {
8327 - buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
8329 - buffer_copy_string_buffer(con->request.uri, con->error_handler);
8331 - buffer_reset(con->physical.path);
8333 - con->in_error_handler = 1;
8335 - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
8339 - } else if (con->in_error_handler) {
8340 - /* error-handler is a 404 */
8342 - /* continue as normal, status is the same */
8343 - log_error_write(srv, __FILE__, __LINE__, "sb",
8344 - "Warning: Either the error-handler returned status 404 or the error-handler itself was not found:", con->request.uri);
8345 - log_error_write(srv, __FILE__, __LINE__, "sd",
8346 - "returning the original status", con->error_handler_saved_status);
8347 - log_error_write(srv, __FILE__, __LINE__, "s",
8348 - "If this is a rails app: check your production.log");
8349 - con->http_status = con->error_handler_saved_status;
8351 - } else if (con->in_error_handler) {
8352 - /* error-handler is back and has generated content */
8353 - /* if Status: was set, take it otherwise use 200 */
8356 - if (con->http_status == 0) con->http_status = 200;
8358 - /* we have something to send, go on */
8359 - connection_set_state(srv, con, CON_STATE_RESPONSE_START);
8361 case HANDLER_WAIT_FOR_FD:
8365 fdwaitqueue_append(srv, con);
8367 - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
8370 + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST_HEADER);
8373 case HANDLER_COMEBACK:
8375 case HANDLER_WAIT_FOR_EVENT:
8376 /* come back here */
8377 - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
8379 + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST_HEADER);
8383 /* something went wrong */
8384 + TRACE("%s", "(error)");
8385 connection_set_state(srv, con, CON_STATE_ERROR);
8388 - log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r);
8389 + TRACE("handle_get_backend returned %d on fd %d", r, con->sock->fd);
8394 + if (r != HANDLER_FINISHED && r != HANDLER_GO_ON) break;
8396 + if (con->http_status == 404 ||
8397 + con->http_status == 403) {
8398 + /* 404 error-handler */
8400 + if (con->in_error_handler == 0 &&
8401 + (!buffer_is_empty(con->conf.error_handler) ||
8402 + !buffer_is_empty(con->error_handler))) {
8403 + /* call error-handler */
8405 + con->error_handler_saved_status = con->http_status;
8406 + con->http_status = 0;
8408 + if (buffer_is_empty(con->error_handler)) {
8409 + buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
8411 + buffer_copy_string_buffer(con->request.uri, con->error_handler);
8413 + buffer_reset(con->physical.path);
8415 + con->in_error_handler = 1;
8417 + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST_HEADER);
8421 + } else if (con->in_error_handler) {
8422 + /* error-handler is a 404 */
8424 + /* continue as normal, status is the same */
8425 + log_error_write(srv, __FILE__, __LINE__, "sb",
8426 + "Warning: Either the error-handler returned status 404 or the error-handler itself was not found:", con->request.uri);
8427 + log_error_write(srv, __FILE__, __LINE__, "sd",
8428 + "returning the original status", con->error_handler_saved_status);
8429 + log_error_write(srv, __FILE__, __LINE__, "s",
8430 + "If this is a rails app: check your production.log");
8431 + con->http_status = con->error_handler_saved_status;
8433 + } else if (con->in_error_handler) {
8434 + /* error-handler is back and has generated content */
8435 + /* if Status: was set, take it otherwise use 200 */
8438 + if (con->http_status == 0) con->http_status = 200;
8440 + /* the backend is prepared, forward the content */
8441 + connection_set_state(srv, con, CON_STATE_READ_REQUEST_CONTENT);
8444 - case CON_STATE_RESPONSE_START:
8445 + case CON_STATE_READ_REQUEST_CONTENT:
8446 + /* the request-handle is setup, read all the data and push it into the request-handler */
8448 + if (con->request.content_length == -1 ||
8449 + con->request.content_length == 0) {
8450 + con->recv->is_closed = 1;
8453 + if (!con->recv->is_closed &&
8454 + con->recv->bytes_in < con->request.content_length) {
8455 + switch (connection_handle_read_request_content(srv, con)) {
8456 + case HANDLER_GO_ON:
8458 + case HANDLER_ERROR:
8459 + TRACE("%s", "(error)");
8460 + connection_set_state(srv, con, CON_STATE_ERROR);
8462 + case HANDLER_WAIT_FOR_EVENT:
8465 + ERROR("%s", "oops, unknown return value: ...");
8468 + if (con->recv->bytes_in == con->request.content_length) {
8469 + TRACE("%s", "read-content-done");
8470 + /* we read everything */
8471 + fdevent_event_del(srv->ev, con->sock);
8472 + con->recv->is_closed = 1;
8474 + chunkqueue_remove_finished_chunks(con->recv_raw);
8477 + chunkqueue_remove_finished_chunks(con->recv);
8480 - * the decision is done
8481 - * - create the HTTP-Response-Header
8482 + * this should call the backend
8483 + * they might build the connection now or stream the content to the upstream server
8486 + switch(r = plugins_call_handle_send_request_content(srv, con)) {
8487 + case HANDLER_GO_ON:
8488 + /* everything was forwarded */
8490 + case HANDLER_FINISHED:
8491 + /* oops, we don't want this here */
8493 + case HANDLER_WAIT_FOR_EVENT:
8494 + return HANDLER_WAIT_FOR_EVENT;
8496 + /* something strange happened */
8497 + TRACE("%s", "(error)");
8498 + connection_set_state(srv, con, CON_STATE_ERROR);
8502 + chunkqueue_remove_finished_chunks(con->recv);
8504 + if (con->state == CON_STATE_ERROR) break;
8506 + if (con->recv->is_closed &&
8507 + con->recv->bytes_in == con->recv->bytes_out) {
8508 + /* everything we read is sent */
8509 + connection_set_state(srv, con, CON_STATE_HANDLE_RESPONSE_HEADER);
8513 + case CON_STATE_HANDLE_RESPONSE_HEADER:
8514 + /* we got a response header from the backend
8515 + * call all plugins who want to modify the response header
8516 + * - mod_compress/deflate
8517 + * - HTTP/1.1 chunking
8521 + connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE_HEADER);
8524 + case CON_STATE_WRITE_RESPONSE_HEADER:
8525 + /* create the HTTP response header */
8526 + connection_handle_response_header(srv, con);
8528 + connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE_CONTENT);
8530 - if (srv->srvconf.log_state_handling) {
8531 - log_error_write(srv, __FILE__, __LINE__, "sds",
8532 - "state for fd", con->fd, connection_get_state(con->state));
8535 - if (-1 == connection_handle_write_prepare(srv, con)) {
8537 + case CON_STATE_WRITE_RESPONSE_CONTENT:
8538 + fdevent_event_del(srv->ev, con->sock);
8540 + /* we might have new content in the con->send buffer
8541 + * encode it for the network
8546 + http_stream_encoder(srv, con, con->send, con->send_raw);
8548 + switch(network_write_chunkqueue(srv, con, con->send_raw)) {
8549 + case NETWORK_STATUS_SUCCESS:
8550 + /* we send everything from the chunkqueue and the chunkqueue-sender signaled it is finished */
8551 + if (con->send->is_closed) {
8552 + if (con->http_status == 100) {
8553 + /* send out the 100 Continue header and handle the request as normal afterwards */
8554 + con->http_status = 0;
8556 + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST_HEADER);
8558 + connection_set_state(srv, con, CON_STATE_RESPONSE_END);
8562 + case NETWORK_STATUS_FATAL_ERROR: /* error on our side */
8563 + TRACE("%s", "(error)");
8564 connection_set_state(srv, con, CON_STATE_ERROR);
8567 + case NETWORK_STATUS_CONNECTION_CLOSE: /* remote close */
8568 + TRACE("%s", "(error)");
8569 + connection_set_state(srv, con, CON_STATE_ERROR);
8571 + case NETWORK_STATUS_WAIT_FOR_EVENT:
8572 + fdevent_event_add(srv->ev, con->sock, FDEVENT_OUT);
8574 + return HANDLER_WAIT_FOR_EVENT;
8575 + case NETWORK_STATUS_INTERRUPTED:
8579 - connection_set_state(srv, con, CON_STATE_WRITE);
8583 case CON_STATE_RESPONSE_END: /* transient */
8584 /* log the request */
8587 if (srv->srvconf.log_state_handling) {
8588 - log_error_write(srv, __FILE__, __LINE__, "sds",
8589 - "state for fd", con->fd, connection_get_state(con->state));
8590 + log_error_write(srv, __FILE__, __LINE__, "sds",
8591 + "state for fd", con->sock->fd, connection_get_state(con->state));
8594 - plugins_call_handle_request_done(srv, con);
8597 + plugins_call_handle_response_done(srv, con);
8602 if (con->keep_alive) {
8603 connection_set_state(srv, con, CON_STATE_REQUEST_START);
8608 con->request_start = srv->cur_ts;
8609 con->read_idle_ts = srv->cur_ts;
8611 @@ -1482,150 +1398,83 @@
8612 log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r);
8617 - if (srv_sock->is_ssl) {
8618 - switch (SSL_shutdown(con->ssl)) {
8623 - /* wait for fd-event
8625 - * FIXME: wait for fdevent and call SSL_shutdown again
8631 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
8632 - ERR_error_string(ERR_get_error(), NULL));
8637 connection_close(srv, con);
8644 connection_reset(srv, con);
8647 - case CON_STATE_CONNECT:
8648 - if (srv->srvconf.log_state_handling) {
8649 - log_error_write(srv, __FILE__, __LINE__, "sds",
8650 - "state for fd", con->fd, connection_get_state(con->state));
8653 - chunkqueue_reset(con->read_queue);
8655 - con->request_count = 0;
8659 case CON_STATE_CLOSE:
8660 if (srv->srvconf.log_state_handling) {
8661 - log_error_write(srv, __FILE__, __LINE__, "sds",
8662 - "state for fd", con->fd, connection_get_state(con->state));
8663 + log_error_write(srv, __FILE__, __LINE__, "sds",
8664 + "state for fd", con->sock->fd, connection_get_state(con->state));
8668 if (con->keep_alive) {
8669 - if (ioctl(con->fd, FIONREAD, &b)) {
8670 + if (ioctl(con->sock->fd, FIONREAD, &b)) {
8671 log_error_write(srv, __FILE__, __LINE__, "ss",
8672 "ioctl() failed", strerror(errno));
8676 log_error_write(srv, __FILE__, __LINE__, "sdd",
8677 - "CLOSE-read()", con->fd, b);
8679 + "CLOSE-read()", con->sock->fd, b);
8682 - read(con->fd, buf, sizeof(buf));
8683 + read(con->sock->fd, buf, sizeof(buf));
8685 /* nothing to read */
8688 con->close_timeout_ts = 0;
8691 con->close_timeout_ts = 0;
8695 if (srv->cur_ts - con->close_timeout_ts > 1) {
8696 connection_close(srv, con);
8699 if (srv->srvconf.log_state_handling) {
8700 - log_error_write(srv, __FILE__, __LINE__, "sd",
8701 - "connection closed for fd", con->fd);
8706 - case CON_STATE_READ_POST:
8707 - case CON_STATE_READ:
8708 - if (srv->srvconf.log_state_handling) {
8709 - log_error_write(srv, __FILE__, __LINE__, "sds",
8710 - "state for fd", con->fd, connection_get_state(con->state));
8713 - connection_handle_read_state(srv, con);
8715 - case CON_STATE_WRITE:
8716 - if (srv->srvconf.log_state_handling) {
8717 - log_error_write(srv, __FILE__, __LINE__, "sds",
8718 - "state for fd", con->fd, connection_get_state(con->state));
8721 - /* only try to write if we have something in the queue */
8722 - if (!chunkqueue_is_empty(con->write_queue)) {
8724 - log_error_write(srv, __FILE__, __LINE__, "dsd",
8726 - "packets to write:",
8727 - con->write_queue->used);
8730 - if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) {
8731 - if (-1 == connection_handle_write(srv, con)) {
8732 - log_error_write(srv, __FILE__, __LINE__, "ds",
8734 - "handle write failed.");
8735 - connection_set_state(srv, con, CON_STATE_ERROR);
8736 - } else if (con->state == CON_STATE_WRITE) {
8737 - con->write_request_ts = srv->cur_ts;
8738 + log_error_write(srv, __FILE__, __LINE__, "sd",
8739 + "connection closed for fd", con->sock->fd);
8745 case CON_STATE_ERROR: /* transient */
8748 /* even if the connection was drop we still have to write it to the access log */
8749 if (con->http_status) {
8750 - plugins_call_handle_request_done(srv, con);
8751 + plugins_call_handle_response_done(srv, con);
8754 if (srv_sock->is_ssl) {
8756 - switch ((ret = SSL_shutdown(con->ssl))) {
8757 + switch ((ret = SSL_shutdown(con->sock->ssl))) {
8762 - SSL_shutdown(con->ssl);
8763 + SSL_shutdown(con->sock->ssl);
8766 - log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
8767 - SSL_get_error(con->ssl, ret),
8768 + log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
8769 + SSL_get_error(con->sock->ssl, ret),
8770 ERR_error_string(ERR_get_error(), NULL));
8780 - log_error_write(srv, __FILE__, __LINE__, "sd",
8781 - "emergency exit: direct",
8783 + log_error_write(srv, __FILE__, __LINE__, "sd",
8784 + "emergency exit: direct",
8789 @@ -1639,35 +1488,35 @@
8795 connection_reset(srv, con);
8798 /* close the connection */
8799 if ((con->keep_alive == 1) &&
8800 - (0 == shutdown(con->fd, SHUT_WR))) {
8801 + (0 == shutdown(con->sock->fd, SHUT_WR))) {
8802 con->close_timeout_ts = srv->cur_ts;
8803 connection_set_state(srv, con, CON_STATE_CLOSE);
8806 if (srv->srvconf.log_state_handling) {
8807 - log_error_write(srv, __FILE__, __LINE__, "sd",
8808 - "shutdown for fd", con->fd);
8809 + log_error_write(srv, __FILE__, __LINE__, "sd",
8810 + "shutdown for fd", con->sock->fd);
8813 connection_close(srv, con);
8817 con->keep_alive = 0;
8825 - log_error_write(srv, __FILE__, __LINE__, "sdd",
8826 - "unknown state:", con->fd, con->state);
8828 + log_error_write(srv, __FILE__, __LINE__, "sdd",
8829 + "unknown state:", con->sock->fd, con->state);
8837 } else if (ostate == con->state) {
8838 @@ -1676,35 +1525,11 @@
8841 if (srv->srvconf.log_state_handling) {
8842 - log_error_write(srv, __FILE__, __LINE__, "sds",
8845 + log_error_write(srv, __FILE__, __LINE__, "sds",
8848 connection_get_state(con->state));
8851 - switch(con->state) {
8852 - case CON_STATE_READ_POST:
8853 - case CON_STATE_READ:
8854 - case CON_STATE_CLOSE:
8855 - fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN);
8857 - case CON_STATE_WRITE:
8858 - /* request write-fdevent only if we really need it
8859 - * - if we have data to write
8860 - * - if the socket is not writable yet
8862 - if (!chunkqueue_is_empty(con->write_queue) &&
8863 - (con->is_writable == 0) &&
8864 - (con->traffic_limit_reached == 0)) {
8865 - fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT);
8867 - fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8871 - fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8877 --- ../lighttpd-1.4.11/src/crc32.h 2005-09-30 20:18:59.000000000 +0300
8878 +++ lighttpd-1.5.0/src/crc32.h 2006-07-16 00:26:04.000000000 +0300
8882 #include <sys/types.h>
8883 +#include <stdlib.h>
8885 #if defined HAVE_STDINT_H
8888 #include <inttypes.h>
8892 +#define uint32_t unsigned __int32
8895 uint32_t generate_crc32c(char *string, size_t length);
8898 --- ../lighttpd-1.4.11/src/data_array.c 2005-08-23 17:36:12.000000000 +0300
8899 +++ lighttpd-1.5.0/src/data_array.c 2006-07-16 00:26:04.000000000 +0300
8902 static void data_array_free(data_unset *d) {
8903 data_array *ds = (data_array *)d;
8906 buffer_free(ds->key);
8907 array_free(ds->value);
8913 static void data_array_reset(data_unset *d) {
8914 data_array *ds = (data_array *)d;
8917 /* reused array elements */
8918 buffer_reset(ds->key);
8919 array_reset(ds->value);
8931 data_array *data_array_init(void) {
8935 ds = calloc(1, sizeof(*ds));
8938 ds->key = buffer_init();
8939 ds->value = array_init();
8942 ds->copy = data_array_copy;
8943 ds->free = data_array_free;
8944 ds->reset = data_array_reset;
8945 ds->insert_dup = data_array_insert_dup;
8946 ds->print = data_array_print;
8947 ds->type = TYPE_ARRAY;
8952 --- ../lighttpd-1.4.11/src/data_config.c 2005-08-17 12:53:19.000000000 +0300
8953 +++ lighttpd-1.5.0/src/data_config.c 2006-07-16 00:26:03.000000000 +0300
8956 static void data_config_free(data_unset *d) {
8957 data_config *ds = (data_config *)d;
8960 buffer_free(ds->key);
8961 buffer_free(ds->op);
8962 buffer_free(ds->comp_key);
8965 array_free(ds->value);
8966 array_free(ds->childs);
8969 if (ds->string) buffer_free(ds->string);
8971 if (ds->regex) pcre_free(ds->regex);
8972 if (ds->regex_study) pcre_free(ds->regex_study);
8979 static void data_config_reset(data_unset *d) {
8980 data_config *ds = (data_config *)d;
8983 /* reused array elements */
8984 buffer_reset(ds->key);
8985 buffer_reset(ds->comp_key);
8988 static int data_config_insert_dup(data_unset *dst, data_unset *src) {
8999 array *a = (array *)ds->value;
9004 if (0 == ds->context_ndx) {
9005 fprintf(stderr, "config {\n");
9007 @@ -117,22 +117,22 @@
9009 data_config *data_config_init(void) {
9013 ds = calloc(1, sizeof(*ds));
9016 ds->key = buffer_init();
9017 ds->op = buffer_init();
9018 ds->comp_key = buffer_init();
9019 ds->value = array_init();
9020 ds->childs = array_init();
9021 ds->childs->is_weakref = 1;
9024 ds->copy = data_config_copy;
9025 ds->free = data_config_free;
9026 ds->reset = data_config_reset;
9027 ds->insert_dup = data_config_insert_dup;
9028 ds->print = data_config_print;
9029 ds->type = TYPE_CONFIG;
9034 --- ../lighttpd-1.4.11/src/data_count.c 2005-08-23 17:36:12.000000000 +0300
9035 +++ lighttpd-1.5.0/src/data_count.c 2006-07-16 00:26:03.000000000 +0300
9038 static void data_count_free(data_unset *d) {
9039 data_count *ds = (data_count *)d;
9042 buffer_free(ds->key);
9048 static void data_count_reset(data_unset *d) {
9049 data_count *ds = (data_count *)d;
9052 buffer_reset(ds->key);
9058 static int data_count_insert_dup(data_unset *dst, data_unset *src) {
9059 data_count *ds_dst = (data_count *)dst;
9060 data_count *ds_src = (data_count *)src;
9063 ds_dst->count += ds_src->count;
9072 static void data_count_print(const data_unset *d, int depth) {
9073 data_count *ds = (data_count *)d;
9077 fprintf(stderr, "count(%d)", ds->count);
9081 data_count *data_count_init(void) {
9085 ds = calloc(1, sizeof(*ds));
9088 ds->key = buffer_init();
9092 ds->copy = data_count_copy;
9093 ds->free = data_count_free;
9094 ds->reset = data_count_reset;
9095 ds->insert_dup = data_count_insert_dup;
9096 ds->print = data_count_print;
9097 ds->type = TYPE_COUNT;
9102 --- ../lighttpd-1.4.11/src/data_fastcgi.c 2005-08-23 17:36:12.000000000 +0300
9103 +++ lighttpd-1.5.0/src/data_fastcgi.c 2006-07-16 00:26:04.000000000 +0300
9106 static void data_fastcgi_free(data_unset *d) {
9107 data_fastcgi *ds = (data_fastcgi *)d;
9110 buffer_free(ds->key);
9111 buffer_free(ds->host);
9117 static void data_fastcgi_reset(data_unset *d) {
9118 data_fastcgi *ds = (data_fastcgi *)d;
9121 buffer_reset(ds->key);
9122 buffer_reset(ds->host);
9127 static int data_fastcgi_insert_dup(data_unset *dst, data_unset *src) {
9136 static void data_fastcgi_print(const data_unset *d, int depth) {
9137 data_fastcgi *ds = (data_fastcgi *)d;
9141 fprintf(stderr, "fastcgi(%s)", ds->host->ptr);
9145 data_fastcgi *data_fastcgi_init(void) {
9149 ds = calloc(1, sizeof(*ds));
9152 ds->key = buffer_init();
9153 ds->host = buffer_init();
9155 ds->is_disabled = 0;
9158 ds->copy = data_fastcgi_copy;
9159 ds->free = data_fastcgi_free;
9160 ds->reset = data_fastcgi_reset;
9161 ds->insert_dup = data_fastcgi_insert_dup;
9162 ds->print = data_fastcgi_print;
9163 ds->type = TYPE_FASTCGI;
9168 --- ../lighttpd-1.4.11/src/data_integer.c 2005-08-23 17:36:12.000000000 +0300
9169 +++ lighttpd-1.5.0/src/data_integer.c 2006-07-16 00:26:03.000000000 +0300
9172 static void data_integer_free(data_unset *d) {
9173 data_integer *ds = (data_integer *)d;
9176 buffer_free(ds->key);
9182 static void data_integer_reset(data_unset *d) {
9183 data_integer *ds = (data_integer *)d;
9186 /* reused integer elements */
9187 buffer_reset(ds->key);
9191 static int data_integer_insert_dup(data_unset *dst, data_unset *src) {
9203 data_integer *data_integer_init(void) {
9207 ds = calloc(1, sizeof(*ds));
9210 ds->key = buffer_init();
9214 ds->copy = data_integer_copy;
9215 ds->free = data_integer_free;
9216 ds->reset = data_integer_reset;
9217 ds->insert_dup = data_integer_insert_dup;
9218 ds->print = data_integer_print;
9219 ds->type = TYPE_INTEGER;
9224 --- ../lighttpd-1.4.11/src/data_string.c 2005-08-23 17:36:12.000000000 +0300
9225 +++ lighttpd-1.5.0/src/data_string.c 2006-07-16 00:26:04.000000000 +0300
9228 static void data_string_free(data_unset *d) {
9229 data_string *ds = (data_string *)d;
9232 buffer_free(ds->key);
9233 buffer_free(ds->value);
9239 static void data_string_reset(data_unset *d) {
9240 data_string *ds = (data_string *)d;
9243 /* reused array elements */
9244 buffer_reset(ds->key);
9245 buffer_reset(ds->value);
9247 static int data_string_insert_dup(data_unset *dst, data_unset *src) {
9248 data_string *ds_dst = (data_string *)dst;
9249 data_string *ds_src = (data_string *)src;
9252 if (ds_dst->value->used) {
9253 buffer_append_string(ds_dst->value, ", ");
9254 buffer_append_string_buffer(ds_dst->value, ds_src->value);
9256 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
9266 static int data_response_insert_dup(data_unset *dst, data_unset *src) {
9267 data_string *ds_dst = (data_string *)dst;
9268 data_string *ds_src = (data_string *)src;
9271 if (ds_dst->value->used) {
9272 buffer_append_string(ds_dst->value, "\r\n");
9273 buffer_append_string_buffer(ds_dst->value, ds_dst->key);
9276 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
9288 data_string *data_string_init(void) {
9292 ds = calloc(1, sizeof(*ds));
9296 ds->key = buffer_init();
9297 ds->value = buffer_init();
9300 ds->copy = data_string_copy;
9301 ds->free = data_string_free;
9302 ds->reset = data_string_reset;
9303 ds->insert_dup = data_string_insert_dup;
9304 ds->print = data_string_print;
9305 ds->type = TYPE_STRING;
9311 data_string *data_response_init(void) {
9315 ds = data_string_init();
9316 ds->insert_dup = data_response_insert_dup;
9321 --- ../lighttpd-1.4.11/src/etag.c 2005-08-11 01:26:40.000000000 +0300
9322 +++ lighttpd-1.5.0/src/etag.c 2006-07-18 13:03:40.000000000 +0300
9326 int etag_is_equal(buffer *etag, const char *matches) {
9327 - if (0 == strcmp(etag->ptr, matches)) return 1;
9328 + if (buffer_is_equal_string(etag, matches, strlen(matches))) return 1;
9333 buffer_append_off_t(etag, st->st_size);
9334 buffer_append_string_len(etag, CONST_STR_LEN("-"));
9335 buffer_append_long(etag, st->st_mtime);
9341 int etag_mutate(buffer *mut, buffer *etag) {
9345 for (h=0, i=0; i < etag->used; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
9349 buffer_copy_string_len(mut, CONST_STR_LEN("\""));
9350 buffer_append_long(mut, h);
9351 buffer_append_string_len(mut, CONST_STR_LEN("\""));
9356 --- ../lighttpd-1.4.11/src/etag.h 2005-08-11 01:26:40.000000000 +0300
9357 +++ lighttpd-1.5.0/src/etag.h 2006-07-16 00:26:03.000000000 +0300
9360 #include <sys/types.h>
9361 #include <sys/stat.h>
9362 -#include <unistd.h>
9366 int etag_is_equal(buffer *etag, const char *matches);
9367 int etag_create(buffer *etag, struct stat *st);
9368 int etag_mutate(buffer *mut, buffer *etag);
9373 --- ../lighttpd-1.4.11/src/fastcgi.h 2005-08-11 01:26:40.000000000 +0300
9374 +++ lighttpd-1.5.0/src/fastcgi.h 2006-07-16 00:26:03.000000000 +0300
9380 * Defines for the FastCGI protocol.
9385 - unsigned char type;
9386 + unsigned char type;
9387 unsigned char reserved[7];
9388 } FCGI_UnknownTypeBody;
9390 --- ../lighttpd-1.4.11/src/fdevent.c 2005-11-15 10:51:05.000000000 +0200
9391 +++ lighttpd-1.5.0/src/fdevent.c 2006-07-18 13:03:40.000000000 +0300
9394 #include "settings.h"
9396 -#include <unistd.h>
9400 @@ -11,60 +10,116 @@
9402 #include "fdevent.h"
9406 +#include "sys-socket.h"
9408 +fdevent_revent *fdevent_revent_init(void) {
9409 + STRUCT_INIT(fdevent_revent, revent);
9414 +void fdevent_revent_free(fdevent_revent *revent) {
9415 + if (!revent) return;
9420 +fdevent_revents *fdevent_revents_init(void) {
9421 + STRUCT_INIT(fdevent_revents, revents);
9426 +void fdevent_revents_reset(fdevent_revents *revents) {
9427 + if (!revents) return;
9429 + revents->used = 0;
9432 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events) {
9433 + fdevent_revent *revent;
9435 + if (revents->used == revents->size) {
9436 + /* resize the events-array */
9437 + revents->ptr = realloc(revents->ptr, (revents->size + 1) * sizeof(*(revents->ptr)));
9438 + revents->ptr[revents->size++] = fdevent_revent_init();
9441 + revent = revents->ptr[revents->used++];
9443 + revent->revents = events;
9446 +void fdevent_revents_free(fdevent_revents *revents) {
9449 + if (!revents) return;
9451 + if (revents->size) {
9452 + for (i = 0; i < revents->size; i++) {
9453 + fdevent_revent_free(revents->ptr[i]);
9456 + free(revents->ptr);
9461 fdevents *fdevent_init(size_t maxfds, fdevent_handler_t type) {
9465 ev = calloc(1, sizeof(*ev));
9466 ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray));
9467 ev->maxfds = maxfds;
9471 case FDEVENT_HANDLER_POLL:
9472 if (0 != fdevent_poll_init(ev)) {
9473 - fprintf(stderr, "%s.%d: event-handler poll failed\n",
9474 + fprintf(stderr, "%s.%d: event-handler poll failed\n",
9475 __FILE__, __LINE__);
9481 case FDEVENT_HANDLER_SELECT:
9482 if (0 != fdevent_select_init(ev)) {
9483 - fprintf(stderr, "%s.%d: event-handler select failed\n",
9484 + fprintf(stderr, "%s.%d: event-handler select failed\n",
9485 __FILE__, __LINE__);
9489 case FDEVENT_HANDLER_LINUX_RTSIG:
9490 if (0 != fdevent_linux_rtsig_init(ev)) {
9491 - fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n",
9492 + fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n",
9493 __FILE__, __LINE__);
9497 case FDEVENT_HANDLER_LINUX_SYSEPOLL:
9498 if (0 != fdevent_linux_sysepoll_init(ev)) {
9499 - fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
9500 + fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
9501 __FILE__, __LINE__);
9505 case FDEVENT_HANDLER_SOLARIS_DEVPOLL:
9506 if (0 != fdevent_solaris_devpoll_init(ev)) {
9507 - fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
9508 + fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
9509 __FILE__, __LINE__);
9513 case FDEVENT_HANDLER_FREEBSD_KQUEUE:
9514 if (0 != fdevent_freebsd_kqueue_init(ev)) {
9515 - fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n",
9516 + fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n",
9517 __FILE__, __LINE__);
9522 - fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n",
9523 + fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n",
9524 __FILE__, __LINE__);
9527 @@ -75,28 +130,29 @@
9528 void fdevent_free(fdevents *ev) {
9533 if (ev->free) ev->free(ev);
9536 for (i = 0; i < ev->maxfds; i++) {
9537 if (ev->fdarray[i]) free(ev->fdarray[i]);
9545 int fdevent_reset(fdevents *ev) {
9546 if (ev->reset) return ev->reset(ev);
9552 fdnode *fdnode_init() {
9556 fdn = calloc(1, sizeof(*fdn));
9562 @@ -104,48 +160,40 @@
9566 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) {
9567 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx) {
9571 fdn = fdnode_init();
9572 fdn->handler = handler;
9574 + fdn->fd = sock->fd;
9577 - ev->fdarray[fd] = fdn;
9579 + ev->fdarray[sock->fd] = fdn;
9584 -int fdevent_unregister(fdevents *ev, int fd) {
9585 +int fdevent_unregister(fdevents *ev, iosocket *sock) {
9588 - fdn = ev->fdarray[fd];
9590 + fdn = ev->fdarray[sock->fd];
9594 - ev->fdarray[fd] = NULL;
9597 + ev->fdarray[sock->fd] = NULL;
9602 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd) {
9603 - int fde = fde_ndx ? *fde_ndx : -1;
9605 - if (ev->event_del) fde = ev->event_del(ev, fde, fd);
9607 - if (fde_ndx) *fde_ndx = fde;
9609 +int fdevent_event_del(fdevents *ev, iosocket *sock) {
9610 + if (ev->event_del) ev->event_del(ev, sock);
9615 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events) {
9616 - int fde = fde_ndx ? *fde_ndx : -1;
9618 - if (ev->event_add) fde = ev->event_add(ev, fde, fd, events);
9620 - if (fde_ndx) *fde_ndx = fde;
9622 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events) {
9623 + if (ev->event_add) ev->event_add(ev, sock, events);
9628 @@ -154,49 +202,41 @@
9629 return ev->poll(ev, timeout_ms);
9632 -int fdevent_event_get_revent(fdevents *ev, size_t ndx) {
9633 - if (ev->event_get_revent == NULL) SEGFAULT();
9635 - return ev->event_get_revent(ev, ndx);
9637 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9640 -int fdevent_event_get_fd(fdevents *ev, size_t ndx) {
9641 - if (ev->event_get_fd == NULL) SEGFAULT();
9643 - return ev->event_get_fd(ev, ndx);
9645 + if (ev->get_revents == NULL) SEGFAULT();
9647 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd) {
9648 - if (ev->fdarray[fd] == NULL) SEGFAULT();
9649 - if (ev->fdarray[fd]->fd != fd) SEGFAULT();
9651 - return ev->fdarray[fd]->handler;
9653 + fdevent_revents_reset(revents);
9655 -void * fdevent_get_context(fdevents *ev, int fd) {
9656 - if (ev->fdarray[fd] == NULL) SEGFAULT();
9657 - if (ev->fdarray[fd]->fd != fd) SEGFAULT();
9659 - return ev->fdarray[fd]->ctx;
9660 + ev->get_revents(ev, event_count, revents);
9662 + /* patch the event handlers */
9663 + for (i = 0; i < event_count; i++) {
9664 + fdevent_revent *r = revents->ptr[i];
9666 + r->handler = ev->fdarray[r->fd]->handler;
9667 + r->context = ev->fdarray[r->fd]->ctx;
9673 -int fdevent_fcntl_set(fdevents *ev, int fd) {
9674 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock) {
9679 /* close fd on exec (cgi) */
9680 - fcntl(fd, F_SETFD, FD_CLOEXEC);
9681 + fcntl(sock->fd, F_SETFD, FD_CLOEXEC);
9683 - if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, fd);
9685 - return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
9686 + if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, sock->fd);
9688 + return fcntl(sock->fd, F_SETFL, O_NONBLOCK | O_RDWR);
9689 +#elif defined _WIN32
9690 + return ioctlsocket(sock->fd, FIONBIO, &i);
9697 -int fdevent_event_next_fdndx(fdevents *ev, int ndx) {
9698 - if (ev->event_next_fdndx) return ev->event_next_fdndx(ev, ndx);
9703 --- ../lighttpd-1.4.11/src/fdevent.h 2005-09-27 11:26:33.000000000 +0300
9704 +++ lighttpd-1.5.0/src/fdevent.h 2006-07-18 13:03:40.000000000 +0300
9706 #include "settings.h"
9709 +#include "iosocket.h"
9710 +#include "array-static.h"
9712 /* select event-system */
9714 #if defined(HAVE_EPOLL_CTL) && defined(HAVE_SYS_EPOLL_H)
9716 # include <sys/epoll.h>
9719 -/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes
9720 +/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes
9721 * under /usr/include/sys/ */
9722 #if defined HAVE_POLL && (defined(HAVE_SYS_POLL_H) || defined(HAVE_POLL_H))
9728 # include <sys/poll.h>
9730 # if defined HAVE_SIGTIMEDWAIT && defined(__linux__)
9732 # include <signal.h>
9737 +# define HAVE_SELECT
9739 #if defined HAVE_SELECT
9742 # include <winsock2.h>
9746 #define FDEVENT_HUP BV(4)
9747 #define FDEVENT_NVAL BV(5)
9749 -typedef enum { FD_EVENT_TYPE_UNSET = -1,
9750 - FD_EVENT_TYPE_CONNECTION,
9751 - FD_EVENT_TYPE_FCGI_CONNECTION,
9752 - FD_EVENT_TYPE_DIRWATCH,
9753 - FD_EVENT_TYPE_CGI_CONNECTION
9754 +typedef enum { FD_EVENT_TYPE_UNSET = -1,
9755 + FD_EVENT_TYPE_CONNECTION,
9756 + FD_EVENT_TYPE_FCGI_CONNECTION,
9757 + FD_EVENT_TYPE_DIRWATCH,
9758 + FD_EVENT_TYPE_CGI_CONNECTION
9761 -typedef enum { FDEVENT_HANDLER_UNSET,
9762 +typedef enum { FDEVENT_HANDLER_UNSET,
9763 FDEVENT_HANDLER_SELECT,
9764 FDEVENT_HANDLER_POLL,
9765 FDEVENT_HANDLER_LINUX_RTSIG,
9769 * a mapping from fd to connection structure
9774 int fd; /**< the fd */
9775 @@ -96,43 +101,51 @@
9779 +ARRAY_STATIC_DEF(fd_conn_buffer, fd_conn, );
9793 + fdevent_handler handler;
9797 +ARRAY_STATIC_DEF(fdevent_revents, fdevent_revent, );
9800 * array of unused fd's
9805 typedef struct _fdnode {
9806 - fdevent_handler handler;
9810 + fdevent_handler handler; /* who handles the events for this fd */
9811 + void *ctx; /* opaque pointer which is passed as 3rd parameter to the handler */
9814 struct _fdnode *prev, *next;
9826 * fd-event handler for select(), poll() and rt-signals on Linux 2.4
9830 typedef struct fdevents {
9831 fdevent_handler_t type;
9835 + fdnode **fdarray; /* a list of fdnodes */
9839 #ifdef USE_LINUX_SIGIO
9842 @@ -146,21 +159,21 @@
9845 struct pollfd *pollfds;
9856 fd_set select_write;
9857 fd_set select_error;
9860 fd_set select_set_read;
9861 fd_set select_set_write;
9862 fd_set select_set_error;
9867 #ifdef USE_SOLARIS_DEVPOLL
9868 @@ -177,16 +190,13 @@
9870 int (*reset)(struct fdevents *ev);
9871 void (*free)(struct fdevents *ev);
9873 - int (*event_add)(struct fdevents *ev, int fde_ndx, int fd, int events);
9874 - int (*event_del)(struct fdevents *ev, int fde_ndx, int fd);
9875 - int (*event_get_revent)(struct fdevents *ev, size_t ndx);
9876 - int (*event_get_fd)(struct fdevents *ev, size_t ndx);
9878 - int (*event_next_fdndx)(struct fdevents *ev, int ndx);
9881 + int (*event_add)(struct fdevents *ev, iosocket *sock, int events);
9882 + int (*event_del)(struct fdevents *ev, iosocket *sock);
9883 + int (*get_revents)(struct fdevents *ev, size_t event_count, fdevent_revents *revents);
9885 int (*poll)(struct fdevents *ev, int timeout_ms);
9888 int (*fcntl_set)(struct fdevents *ev, int fd);
9891 @@ -194,22 +204,44 @@
9892 int fdevent_reset(fdevents *ev);
9893 void fdevent_free(fdevents *ev);
9895 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events);
9896 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd);
9897 -int fdevent_event_get_revent(fdevents *ev, size_t ndx);
9898 -int fdevent_event_get_fd(fdevents *ev, size_t ndx);
9899 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd);
9900 -void * fdevent_get_context(fdevents *ev, int fd);
9902 + * call the plugin for the number of available events
9904 +int fdevent_poll(fdevents *ev, int timeout_ms);
9906 + * get all available events
9908 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents);
9910 -int fdevent_event_next_fdndx(fdevents *ev, int ndx);
9912 + * add or remove a fd to the handled-pool
9914 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx);
9915 +int fdevent_unregister(fdevents *ev, iosocket *sock);
9917 -int fdevent_poll(fdevents *ev, int timeout_ms);
9919 + * add a event to a registered fd
9921 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events);
9922 +int fdevent_event_del(fdevents *ev, iosocket *sock);
9925 + * set non-blocking
9927 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock);
9929 +fdevent_revents *fdevent_revents_init(void);
9930 +void fdevent_revents_reset(fdevent_revents *revents);
9931 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events);
9932 +void fdevent_revents_free(fdevent_revents *revents);
9934 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx);
9935 -int fdevent_unregister(fdevents *ev, int fd);
9936 +fdevent_revent *fdevent_revent_init(void);
9937 +void fdevent_revent_free(fdevent_revent *revent);
9939 -int fdevent_fcntl_set(fdevents *ev, int fd);
9944 int fdevent_select_init(fdevents *ev);
9945 int fdevent_poll_init(fdevents *ev);
9946 int fdevent_linux_rtsig_init(fdevents *ev);
9947 --- ../lighttpd-1.4.11/src/fdevent_freebsd_kqueue.c 2005-09-01 10:46:24.000000000 +0300
9948 +++ lighttpd-1.5.0/src/fdevent_freebsd_kqueue.c 2006-09-07 00:57:05.000000000 +0300
9950 #include <sys/types.h>
9952 -#include <unistd.h>
9957 #include <sys/event.h>
9958 #include <sys/time.h>
9960 +#include "sys-files.h"
9962 static void fdevent_freebsd_kqueue_free(fdevents *ev) {
9964 free(ev->kq_results);
9965 bitset_free(ev->kq_bevents);
9968 -static int fdevent_freebsd_kqueue_event_del(fdevents *ev, int fde_ndx, int fd) {
9969 +static int fdevent_freebsd_kqueue_event_del(fdevents *ev, iosocket *sock) {
9974 - if (fde_ndx < 0) return -1;
9975 + if (sock->fde_ndx < 0) return -1;
9977 - filter = bitset_test_bit(ev->kq_bevents, fd) ? EVFILT_READ : EVFILT_WRITE;
9978 + filter = bitset_test_bit(ev->kq_bevents, sock->fd) ? EVFILT_READ : EVFILT_WRITE;
9980 - EV_SET(&kev, fd, filter, EV_DELETE, 0, 0, NULL);
9981 + EV_SET(&kev, sock->fd, filter, EV_DELETE, 0, 0, NULL);
9989 + sock->fde_ndx = -1;
9991 fprintf(stderr, "%s.%d: kqueue failed polling: %s\n",
9992 __FILE__, __LINE__, strerror(errno));
10003 -static int fdevent_freebsd_kqueue_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
10004 +static int fdevent_freebsd_kqueue_event_add(fdevents *ev, iosocket *sock, int events) {
10007 struct timespec ts;
10011 filter = (events & FDEVENT_IN) ? EVFILT_READ : EVFILT_WRITE;
10013 - EV_SET(&kev, fd, filter, EV_ADD|EV_CLEAR, 0, 0, NULL);
10014 + EV_SET(&kev, sock->fd, filter, EV_ADD|EV_CLEAR, 0, 0, NULL);
10020 ret = kevent(ev->kq_fd,
10023 @@ -77,14 +77,14 @@
10029 if (filter == EVFILT_READ) {
10030 - bitset_set_bit(ev->kq_bevents, fd);
10031 + bitset_set_bit(ev->kq_bevents, sock->fd);
10033 - bitset_clear_bit(ev->kq_bevents, fd);
10034 + bitset_clear_bit(ev->kq_bevents, sock->fd);
10041 static int fdevent_freebsd_kqueue_poll(fdevents *ev, int timeout_ms) {
10042 @@ -114,48 +114,44 @@
10046 -static int fdevent_freebsd_kqueue_event_get_revent(fdevents *ev, size_t ndx) {
10047 - int events = 0, e;
10048 +static int fdevent_freebsd_kqueue_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
10051 - e = ev->kq_results[ndx].filter;
10053 - if (e == EVFILT_READ) {
10054 - events |= FDEVENT_IN;
10055 - } else if (e == EVFILT_WRITE) {
10056 - events |= FDEVENT_OUT;
10059 - e = ev->kq_results[ndx].flags;
10060 + for (ndx = 0; ndx < ev->used; ndx++) {
10061 + int events = 0, e;
10063 - if (e & EV_EOF) {
10064 - events |= FDEVENT_HUP;
10066 + e = ev->kq_results[ndx].filter;
10068 - if (e & EV_ERROR) {
10069 - events |= FDEVENT_ERR;
10071 + if (e == EVFILT_READ) {
10072 + events |= FDEVENT_IN;
10073 + } else if (e == EVFILT_WRITE) {
10074 + events |= FDEVENT_OUT;
10079 + e = ev->kq_results[ndx].flags;
10081 -static int fdevent_freebsd_kqueue_event_get_fd(fdevents *ev, size_t ndx) {
10082 - return ev->kq_results[ndx].ident;
10084 + if (e & EV_EOF) {
10085 + events |= FDEVENT_HUP;
10088 + if (e & EV_ERROR) {
10089 + events |= FDEVENT_ERR;
10092 -static int fdevent_freebsd_kqueue_event_next_fdndx(fdevents *ev, int ndx) {
10094 + fdevent_revents_add(revents, ev->kq_results[ndx].ident, events);
10097 - return (ndx < 0) ? 0 : ndx + 1;
10101 static int fdevent_freebsd_kqueue_reset(fdevents *ev) {
10102 if (-1 == (ev->kq_fd = kqueue())) {
10103 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
10104 __FILE__, __LINE__, strerror(errno));
10114 @@ -172,9 +168,7 @@
10118 - SET(event_next_fdndx);
10119 - SET(event_get_fd);
10120 - SET(event_get_revent);
10121 + SET(get_revents);
10125 @@ -186,7 +180,7 @@
10126 if (-1 == (ev->kq_fd = kqueue())) {
10127 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
10128 __FILE__, __LINE__, strerror(errno));
10134 --- ../lighttpd-1.4.11/src/fdevent_linux_rtsig.c 2005-11-21 19:56:11.000000000 +0200
10135 +++ lighttpd-1.5.0/src/fdevent_linux_rtsig.c 2006-07-18 13:03:40.000000000 +0300
10137 #include <sys/types.h>
10139 -#include <unistd.h>
10140 #include <stdlib.h>
10142 #include <string.h>
10144 #include "fdevent.h"
10145 #include "settings.h"
10146 #include "buffer.h"
10147 +#include "sys-process.h"
10150 #ifdef USE_LINUX_SIGIO
10151 static void fdevent_linux_rtsig_free(fdevents *ev) {
10152 @@ -24,21 +25,21 @@
10156 -static int fdevent_linux_rtsig_event_del(fdevents *ev, int fde_ndx, int fd) {
10157 - if (fde_ndx < 0) return -1;
10159 - if ((size_t)fde_ndx >= ev->used) {
10160 - fprintf(stderr, "%s.%d: del! out of range %d %zu\n", __FILE__, __LINE__, fde_ndx, ev->used);
10161 +static int fdevent_linux_rtsig_event_del(fdevents *ev, iosocket *sock) {
10162 + if (sock->fde_ndx < 0) return -1;
10164 + if ((size_t)sock->fde_ndx >= ev->used) {
10165 + TRACE("del! out of range %d %zu\n", sock->fde_ndx, ev->used);
10169 - if (ev->pollfds[fde_ndx].fd == fd) {
10170 - size_t k = fde_ndx;
10173 + if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
10174 + size_t k = sock->fde_ndx;
10176 ev->pollfds[k].fd = -1;
10178 - bitset_clear_bit(ev->sigbset, fd);
10180 + bitset_clear_bit(ev->sigbset, sock->fd);
10182 if (ev->unused.size == 0) {
10183 ev->unused.size = 16;
10184 ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
10185 @@ -46,53 +47,54 @@
10186 ev->unused.size += 16;
10187 ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
10191 ev->unused.ptr[ev->unused.used++] = k;
10193 - fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[fde_ndx].fd, fd);
10195 + fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[sock->fde_ndx].fd, sock->fd);
10201 + sock->fde_ndx = -1;
10207 static int fdevent_linux_rtsig_event_compress(fdevents *ev) {
10211 if (ev->used == 0) return 0;
10212 if (ev->unused.used != 0) return 0;
10215 for (j = ev->used - 1; j + 1 > 0; j--) {
10216 if (ev->pollfds[j].fd == -1) ev->used--;
10226 -static int fdevent_linux_rtsig_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
10227 +static int fdevent_linux_rtsig_event_add(fdevents *ev, iosocket *sock, int events) {
10229 - if (fde_ndx != -1) {
10230 - if (ev->pollfds[fde_ndx].fd == fd) {
10231 - ev->pollfds[fde_ndx].events = events;
10234 + if (sock->fde_ndx != -1) {
10235 + if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
10236 + ev->pollfds[sock->fde_ndx].events = events;
10238 + return sock->fde_ndx;
10240 - fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
10241 + fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
10246 if (ev->unused.used > 0) {
10247 int k = ev->unused.ptr[--ev->unused.used];
10249 - ev->pollfds[k].fd = fd;
10251 + ev->pollfds[k].fd = sock->fd;
10252 ev->pollfds[k].events = events;
10254 - bitset_set_bit(ev->sigbset, fd);
10256 + bitset_set_bit(ev->sigbset, sock->fd);
10260 if (ev->size == 0) {
10261 @@ -102,12 +104,12 @@
10263 ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
10266 - ev->pollfds[ev->used].fd = fd;
10268 + ev->pollfds[ev->used].fd = sock->fd;
10269 ev->pollfds[ev->used].events = events;
10271 - bitset_set_bit(ev->sigbset, fd);
10273 + bitset_set_bit(ev->sigbset, sock->fd);
10278 @@ -115,20 +117,20 @@
10279 static int fdevent_linux_rtsig_poll(fdevents *ev, int timeout_ms) {
10280 struct timespec ts;
10285 fdevent_linux_rtsig_event_compress(ev);
10292 ts.tv_sec = timeout_ms / 1000;
10293 ts.tv_nsec = (timeout_ms % 1000) * 1000000;
10294 r = sigtimedwait(&(ev->sigset), &(ev->siginfo), &(ts));
10299 if (errno == EAGAIN) return 0;
10302 } else if (r == SIGIO) {
10303 struct sigaction act;
10305 @@ -140,7 +142,7 @@
10306 /* re-enable the signal queue */
10307 act.sa_handler = SIG_DFL;
10308 sigaction(ev->signum, &act, NULL);
10312 r = poll(ev->pollfds, ev->used, timeout_ms);
10314 @@ -156,97 +158,67 @@
10318 -static int fdevent_linux_rtsig_event_get_revent(fdevents *ev, size_t ndx) {
10319 +static int fdevent_linux_rtsig_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
10320 if (ev->in_sigio == 1) {
10322 - if (ev->siginfo.si_band == POLLERR) {
10323 - fprintf(stderr, "event: %d %02lx %02x %s\n", ev->siginfo.si_fd, ev->siginfo.si_band, errno, strerror(errno));
10327 - fprintf(stderr, "+\n");
10331 - return ev->siginfo.si_band & 0x3f;
10332 + /* only one event */
10334 + fdevent_revents_add(revents, ev->siginfo.si_fd, ev->siginfo.si_band & 0x3f);
10336 - if (ndx >= ev->used) {
10337 - fprintf(stderr, "%s.%d: event: %zu %zu\n", __FILE__, __LINE__, ndx, ev->used);
10341 + for (ndx = 0; ndx < ev->used; ndx++) {
10342 + if (ev->pollfds[ndx].revents) {
10343 + fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
10346 - return ev->pollfds[ndx].revents;
10350 -static int fdevent_linux_rtsig_event_get_fd(fdevents *ev, size_t ndx) {
10351 - if (ev->in_sigio == 1) {
10352 - return ev->siginfo.si_fd;
10354 - return ev->pollfds[ndx].fd;
10359 static int fdevent_linux_rtsig_fcntl_set(fdevents *ev, int fd) {
10360 static pid_t pid = 0;
10363 if (pid == 0) pid = getpid();
10366 if (-1 == fcntl(fd, F_SETSIG, ev->signum)) return -1;
10369 if (-1 == fcntl(fd, F_SETOWN, (int) pid)) return -1;
10372 return fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK | O_RDWR);
10376 -static int fdevent_linux_rtsig_event_next_fdndx(fdevents *ev, int ndx) {
10377 - if (ev->in_sigio == 1) {
10378 - if (ndx < 0) return 0;
10383 - i = (ndx < 0) ? 0 : ndx + 1;
10384 - for (; i < ev->used; i++) {
10385 - if (ev->pollfds[i].revents) break;
10392 int fdevent_linux_rtsig_init(fdevents *ev) {
10393 ev->type = FDEVENT_HANDLER_LINUX_RTSIG;
10395 ev->x = fdevent_linux_rtsig_##x;
10405 - SET(event_next_fdndx);
10408 - SET(event_get_fd);
10409 - SET(event_get_revent);
10411 + SET(get_revents);
10413 ev->signum = SIGRTMIN + 1;
10416 sigemptyset(&(ev->sigset));
10417 sigaddset(&(ev->sigset), ev->signum);
10418 sigaddset(&(ev->sigset), SIGIO);
10419 if (-1 == sigprocmask(SIG_BLOCK, &(ev->sigset), NULL)) {
10420 fprintf(stderr, "%s.%d: sigprocmask failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
10421 __FILE__, __LINE__, strerror(errno));
10430 ev->sigbset = bitset_init(ev->maxfds);
10436 --- ../lighttpd-1.4.11/src/fdevent_linux_sysepoll.c 2005-09-30 20:29:27.000000000 +0300
10437 +++ lighttpd-1.5.0/src/fdevent_linux_sysepoll.c 2006-07-18 13:03:40.000000000 +0300
10439 #include <sys/types.h>
10441 -#include <unistd.h>
10442 #include <stdlib.h>
10444 #include <string.h>
10446 #include "fdevent.h"
10447 #include "settings.h"
10448 #include "buffer.h"
10451 +#include "sys-files.h"
10453 #ifdef USE_LINUX_EPOLL
10454 static void fdevent_linux_sysepoll_free(fdevents *ev) {
10455 @@ -18,38 +20,40 @@
10456 free(ev->epoll_events);
10459 -static int fdevent_linux_sysepoll_event_del(fdevents *ev, int fde_ndx, int fd) {
10460 +static int fdevent_linux_sysepoll_event_del(fdevents *ev, iosocket *sock) {
10461 struct epoll_event ep;
10463 - if (fde_ndx < 0) return -1;
10466 + if (sock->fde_ndx < 0) return -1;
10468 memset(&ep, 0, sizeof(ep));
10472 + ep.data.fd = sock->fd;
10473 ep.data.ptr = NULL;
10475 - if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fd, &ep)) {
10477 + if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, sock->fd, &ep)) {
10478 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
10490 + sock->fde_ndx = -1;
10495 -static int fdevent_linux_sysepoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
10496 +static int fdevent_linux_sysepoll_event_add(fdevents *ev, iosocket *sock, int events) {
10497 struct epoll_event ep;
10500 - if (fde_ndx == -1) add = 1;
10504 + if (sock->fde_ndx == -1) add = 1;
10506 memset(&ep, 0, sizeof(ep));
10512 if (events & FDEVENT_IN) ep.events |= EPOLLIN;
10513 if (events & FDEVENT_OUT) ep.events |= EPOLLOUT;
10515 @@ -60,73 +64,61 @@
10521 ep.events |= EPOLLERR | EPOLLHUP /* | EPOLLET */;
10524 ep.data.ptr = NULL;
10527 - if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &ep)) {
10528 + ep.data.fd = sock->fd;
10530 + if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, sock->fd, &ep)) {
10531 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
10542 + sock->fde_ndx = sock->fd;
10547 static int fdevent_linux_sysepoll_poll(fdevents *ev, int timeout_ms) {
10548 return epoll_wait(ev->epoll_fd, ev->epoll_events, ev->maxfds, timeout_ms);
10551 -static int fdevent_linux_sysepoll_event_get_revent(fdevents *ev, size_t ndx) {
10552 - int events = 0, e;
10554 - e = ev->epoll_events[ndx].events;
10555 - if (e & EPOLLIN) events |= FDEVENT_IN;
10556 - if (e & EPOLLOUT) events |= FDEVENT_OUT;
10557 - if (e & EPOLLERR) events |= FDEVENT_ERR;
10558 - if (e & EPOLLHUP) events |= FDEVENT_HUP;
10559 - if (e & EPOLLPRI) events |= FDEVENT_PRI;
10564 -static int fdevent_linux_sysepoll_event_get_fd(fdevents *ev, size_t ndx) {
10566 - fprintf(stderr, "%s.%d: %d, %d\n", __FILE__, __LINE__, ndx, ev->epoll_events[ndx].data.fd);
10569 - return ev->epoll_events[ndx].data.fd;
10572 -static int fdevent_linux_sysepoll_event_next_fdndx(fdevents *ev, int ndx) {
10576 +static int fdevent_linux_sysepoll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
10579 + for (ndx = 0; ndx < event_count; ndx++) {
10580 + int events = 0, e;
10582 + e = ev->epoll_events[ndx].events;
10583 + if (e & EPOLLIN) events |= FDEVENT_IN;
10584 + if (e & EPOLLOUT) events |= FDEVENT_OUT;
10585 + if (e & EPOLLERR) events |= FDEVENT_ERR;
10586 + if (e & EPOLLHUP) events |= FDEVENT_HUP;
10587 + if (e & EPOLLPRI) events |= FDEVENT_PRI;
10589 - i = (ndx < 0) ? 0 : ndx + 1;
10592 + fdevent_revents_add(revents, ev->epoll_events[ndx].data.fd, e);
10598 int fdevent_linux_sysepoll_init(fdevents *ev) {
10599 ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
10601 ev->x = fdevent_linux_sysepoll_##x;
10611 - SET(event_next_fdndx);
10612 - SET(event_get_fd);
10613 - SET(event_get_revent);
10616 + SET(get_revents);
10618 if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) {
10619 fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
10620 __FILE__, __LINE__, strerror(errno));
10621 @@ -154,7 +146,7 @@
10623 fprintf(stderr, "%s.%d: linux-sysepoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
10624 __FILE__, __LINE__);
10630 --- ../lighttpd-1.4.11/src/fdevent_poll.c 2005-11-18 13:59:16.000000000 +0200
10631 +++ lighttpd-1.5.0/src/fdevent_poll.c 2006-09-07 00:57:05.000000000 +0300
10633 #include <sys/types.h>
10635 -#include <unistd.h>
10636 #include <stdlib.h>
10638 #include <string.h>
10640 #include "fdevent.h"
10641 #include "settings.h"
10642 #include "buffer.h"
10646 static void fdevent_poll_free(fdevents *ev) {
10647 @@ -18,21 +18,21 @@
10648 if (ev->unused.ptr) free(ev->unused.ptr);
10651 -static int fdevent_poll_event_del(fdevents *ev, int fde_ndx, int fd) {
10652 - if (fde_ndx < 0) return -1;
10654 - if ((size_t)fde_ndx >= ev->used) {
10655 - fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, fde_ndx, ev->used);
10656 +static int fdevent_poll_event_del(fdevents *ev, iosocket *sock) {
10657 + if (sock->fde_ndx < 0) return -1;
10659 + if ((size_t)sock->fde_ndx >= ev->used) {
10660 + fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, sock->fde_ndx, ev->used);
10664 - if (ev->pollfds[fde_ndx].fd == fd) {
10665 - size_t k = fde_ndx;
10668 + if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
10669 + size_t k = sock->fde_ndx;
10671 ev->pollfds[k].fd = -1;
10672 /* ev->pollfds[k].events = 0; */
10673 /* ev->pollfds[k].revents = 0; */
10676 if (ev->unused.size == 0) {
10677 ev->unused.size = 16;
10678 ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
10679 @@ -40,48 +40,52 @@
10680 ev->unused.size += 16;
10681 ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
10685 ev->unused.ptr[ev->unused.used++] = k;
10687 + TRACE("(fdevent-poll-del) sock->fde_ndx: %d, sock->fd: %d -> stored fd: %d", sock->fde_ndx, sock->fd, ev->pollfds[sock->fde_ndx].fd);
10693 + sock->fde_ndx = -1;
10699 static int fdevent_poll_event_compress(fdevents *ev) {
10703 if (ev->used == 0) return 0;
10704 if (ev->unused.used != 0) return 0;
10707 for (j = ev->used - 1; j + 1 > 0 && ev->pollfds[j].fd == -1; j--) ev->used--;
10714 -static int fdevent_poll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
10715 - /* known index */
10717 - if (fde_ndx != -1) {
10718 - if (ev->pollfds[fde_ndx].fd == fd) {
10719 - ev->pollfds[fde_ndx].events = events;
10722 +static int fdevent_poll_event_add(fdevents *ev, iosocket *sock, int events) {
10723 + if (sock->fde_ndx != -1) {
10724 + /* this fd was already added, just change the requested events */
10726 + if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
10727 + ev->pollfds[sock->fde_ndx].events = events;
10729 + return sock->fde_ndx;
10731 - fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
10732 + fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
10737 if (ev->unused.used > 0) {
10738 int k = ev->unused.ptr[--ev->unused.used];
10740 - ev->pollfds[k].fd = fd;
10742 + ev->pollfds[k].fd = sock->fd;
10743 ev->pollfds[k].events = events;
10747 + sock->fde_ndx = k;
10750 if (ev->size == 0) {
10752 @@ -90,12 +94,13 @@
10754 ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
10757 - ev->pollfds[ev->used].fd = fd;
10759 + ev->pollfds[ev->used].fd = sock->fd;
10760 ev->pollfds[ev->used].events = events;
10762 - return ev->used++;
10764 + sock->fde_ndx = ev->used++;
10769 static int fdevent_poll_poll(fdevents *ev, int timeout_ms) {
10770 @@ -105,71 +110,38 @@
10771 return poll(ev->pollfds, ev->used, timeout_ms);
10774 -static int fdevent_poll_event_get_revent(fdevents *ev, size_t ndx) {
10776 - if (ndx >= ev->used) {
10777 - fprintf(stderr, "%s.%d: dying because: event: %zd >= %zd\n", __FILE__, __LINE__, ndx, ev->used);
10784 - if (ev->pollfds[ndx].revents & POLLNVAL) {
10785 - /* should never happen */
10788 +static int fdevent_poll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
10792 - poll_r = ev->pollfds[ndx].revents;
10793 + for (ndx = 0; ndx < ev->used; ndx++) {
10794 + if (ev->pollfds[ndx].revents) {
10795 + if (ev->pollfds[ndx].revents & POLLNVAL) {
10796 + /* should never happen */
10800 - /* map POLL* to FDEVEN_* */
10802 - if (poll_r & POLLIN) r |= FDEVENT_IN;
10803 - if (poll_r & POLLOUT) r |= FDEVENT_OUT;
10804 - if (poll_r & POLLERR) r |= FDEVENT_ERR;
10805 - if (poll_r & POLLHUP) r |= FDEVENT_HUP;
10806 - if (poll_r & POLLNVAL) r |= FDEVENT_NVAL;
10807 - if (poll_r & POLLPRI) r |= FDEVENT_PRI;
10809 - return ev->pollfds[ndx].revents;
10812 -static int fdevent_poll_event_get_fd(fdevents *ev, size_t ndx) {
10813 - return ev->pollfds[ndx].fd;
10816 -static int fdevent_poll_event_next_fdndx(fdevents *ev, int ndx) {
10819 - i = (ndx < 0) ? 0 : ndx + 1;
10820 - for (; i < ev->used; i++) {
10821 - if (ev->pollfds[i].revents) break;
10822 + fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
10831 int fdevent_poll_init(fdevents *ev) {
10832 ev->type = FDEVENT_HANDLER_POLL;
10834 ev->x = fdevent_poll_##x;
10844 - SET(event_next_fdndx);
10845 - SET(event_get_fd);
10846 - SET(event_get_revent);
10852 + SET(get_revents);
10858 int fdevent_poll_init(fdevents *ev) {
10859 --- ../lighttpd-1.4.11/src/fdevent_select.c 2005-08-31 11:12:46.000000000 +0300
10860 +++ lighttpd-1.5.0/src/fdevent_select.c 2006-07-18 13:03:40.000000000 +0300
10862 -#include <sys/time.h>
10863 #include <sys/types.h>
10865 -#include <unistd.h>
10866 #include <stdlib.h>
10867 #include <string.h>
10869 #include <signal.h>
10871 #include <assert.h>
10872 +#include <stdio.h>
10874 #include "fdevent.h"
10875 #include "settings.h"
10876 #include "buffer.h"
10878 +#include "sys-socket.h"
10882 static int fdevent_select_reset(fdevents *ev) {
10883 @@ -24,101 +25,98 @@
10887 -static int fdevent_select_event_del(fdevents *ev, int fde_ndx, int fd) {
10888 - if (fde_ndx < 0) return -1;
10889 +static int fdevent_select_event_del(fdevents *ev, iosocket *sock) {
10890 + if (sock->fde_ndx < 0) return -1;
10892 - FD_CLR(fd, &(ev->select_set_read));
10893 - FD_CLR(fd, &(ev->select_set_write));
10894 - FD_CLR(fd, &(ev->select_set_error));
10895 + FD_CLR(sock->fd, &(ev->select_set_read));
10896 + FD_CLR(sock->fd, &(ev->select_set_write));
10897 + FD_CLR(sock->fd, &(ev->select_set_error));
10901 + /* mark the fdevent as deleted */
10902 + sock->fde_ndx = -1;
10904 -static int fdevent_select_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
10909 +static int fdevent_select_event_add(fdevents *ev, iosocket *sock, int events) {
10910 /* we should be protected by max-fds, but you never know */
10911 - assert(fd < FD_SETSIZE);
10913 + assert(sock->fd < FD_SETSIZE);
10916 if (events & FDEVENT_IN) {
10917 - FD_SET(fd, &(ev->select_set_read));
10918 - FD_CLR(fd, &(ev->select_set_write));
10919 + FD_SET(sock->fd, &(ev->select_set_read));
10920 + FD_CLR(sock->fd, &(ev->select_set_write));
10922 if (events & FDEVENT_OUT) {
10923 - FD_CLR(fd, &(ev->select_set_read));
10924 - FD_SET(fd, &(ev->select_set_write));
10925 + FD_CLR(sock->fd, &(ev->select_set_read));
10926 + FD_SET(sock->fd, &(ev->select_set_write));
10928 - FD_SET(fd, &(ev->select_set_error));
10930 - if (fd > ev->select_max_fd) ev->select_max_fd = fd;
10933 + FD_SET(sock->fd, &(ev->select_set_error));
10935 + /* we need this for the poll */
10936 + if (sock->fd > ev->select_max_fd) ev->select_max_fd = sock->fd;
10938 + /* mark fd as added */
10939 + sock->fde_ndx = sock->fd;
10944 static int fdevent_select_poll(fdevents *ev, int timeout_ms) {
10948 tv.tv_sec = timeout_ms / 1000;
10949 tv.tv_usec = (timeout_ms % 1000) * 1000;
10952 ev->select_read = ev->select_set_read;
10953 ev->select_write = ev->select_set_write;
10954 ev->select_error = ev->select_set_error;
10957 return select(ev->select_max_fd + 1, &(ev->select_read), &(ev->select_write), &(ev->select_error), &tv);
10960 -static int fdevent_select_event_get_revent(fdevents *ev, size_t ndx) {
10963 - if (FD_ISSET(ndx, &(ev->select_read))) {
10964 - revents |= FDEVENT_IN;
10966 + * scan the fdset for events
10968 +static int fdevent_select_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
10972 + for (ndx = 0; ndx < ev->select_max_fd; ndx++) {
10975 + if (FD_ISSET(ndx, &(ev->select_read))) {
10976 + events |= FDEVENT_IN;
10978 + if (FD_ISSET(ndx, &(ev->select_write))) {
10979 + events |= FDEVENT_OUT;
10981 + if (FD_ISSET(ndx, &(ev->select_error))) {
10982 + events |= FDEVENT_ERR;
10986 + fdevent_revents_add(revents, ndx, events);
10989 - if (FD_ISSET(ndx, &(ev->select_write))) {
10990 - revents |= FDEVENT_OUT;
10992 - if (FD_ISSET(ndx, &(ev->select_error))) {
10993 - revents |= FDEVENT_ERR;
10999 -static int fdevent_select_event_get_fd(fdevents *ev, size_t ndx) {
11005 -static int fdevent_select_event_next_fdndx(fdevents *ev, int ndx) {
11008 - i = (ndx < 0) ? 0 : ndx + 1;
11010 - for (; i < ev->select_max_fd + 1; i++) {
11011 - if (FD_ISSET(i, &(ev->select_read))) break;
11012 - if (FD_ISSET(i, &(ev->select_write))) break;
11013 - if (FD_ISSET(i, &(ev->select_error))) break;
11020 int fdevent_select_init(fdevents *ev) {
11021 ev->type = FDEVENT_HANDLER_SELECT;
11023 ev->x = fdevent_select_##x;
11033 - SET(event_next_fdndx);
11034 - SET(event_get_fd);
11035 - SET(event_get_revent);
11038 + SET(get_revents);
11043 --- ../lighttpd-1.4.11/src/fdevent_solaris_devpoll.c 2005-09-01 10:45:26.000000000 +0300
11044 +++ lighttpd-1.5.0/src/fdevent_solaris_devpoll.c 2006-07-16 00:26:03.000000000 +0300
11046 #include <sys/types.h>
11048 -#include <unistd.h>
11049 #include <stdlib.h>
11051 #include <string.h>
11052 @@ -23,55 +22,55 @@
11054 static int fdevent_solaris_devpoll_event_del(fdevents *ev, int fde_ndx, int fd) {
11058 if (fde_ndx < 0) return -1;
11062 pfd.events = POLLREMOVE;
11066 if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
11067 - fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
11068 - __FILE__, __LINE__,
11069 + fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
11070 + __FILE__, __LINE__,
11071 fd, strerror(errno));
11081 static int fdevent_solaris_devpoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
11086 if (fde_ndx == -1) add = 1;
11090 pfd.events = events;
11094 if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
11095 - fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
11096 - __FILE__, __LINE__,
11097 + fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
11098 + __FILE__, __LINE__,
11099 fd, strerror(errno));
11109 static int fdevent_solaris_devpoll_poll(fdevents *ev, int timeout_ms) {
11110 struct dvpoll dopoll;
11114 dopoll.dp_timeout = timeout_ms;
11115 dopoll.dp_nfds = ev->maxfds;
11116 dopoll.dp_fds = ev->devpollfds;
11119 ret = ioctl(ev->devpoll_fd, DP_POLL, &dopoll);
11125 @@ -85,11 +84,11 @@
11127 static int fdevent_solaris_devpoll_event_next_fdndx(fdevents *ev, int last_ndx) {
11133 i = (last_ndx < 0) ? 0 : last_ndx + 1;
11139 @@ -117,20 +116,20 @@
11140 ev->type = FDEVENT_HANDLER_SOLARIS_DEVPOLL;
11142 ev->x = fdevent_solaris_devpoll_##x;
11154 SET(event_next_fdndx);
11156 SET(event_get_revent);
11159 ev->devpollfds = malloc(sizeof(*ev->devpollfds) * ev->maxfds);
11162 if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
11163 fprintf(stderr, "%s.%d: opening /dev/poll failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
11164 __FILE__, __LINE__, strerror(errno));
11165 @@ -152,7 +151,7 @@
11167 fprintf(stderr, "%s.%d: solaris-devpoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
11168 __FILE__, __LINE__);
11174 --- ../lighttpd-1.4.11/src/http-header-glue.c 2006-02-08 15:31:36.000000000 +0200
11175 +++ lighttpd-1.5.0/src/http-header-glue.c 2006-09-07 00:57:05.000000000 +0300
11176 @@ -45,20 +45,20 @@
11177 # ifdef HAVE_STRUCT_SOCKADDR_STORAGE
11178 static size_t get_sa_len(const struct sockaddr *addr) {
11179 switch (addr->sa_family) {
11184 return (sizeof (struct sockaddr_in));
11190 return (sizeof (struct sockaddr_in6));
11195 return (sizeof (struct sockaddr));
11200 # define SA_LEN(addr) (get_sa_len(addr))
11203 int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
11209 if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
11210 @@ -82,32 +82,32 @@
11212 buffer_copy_string_len(ds->key, key, keylen);
11213 buffer_copy_string_len(ds->value, value, vallen);
11216 array_insert_unique(con->response.headers, (data_unset *)ds);
11222 int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
11228 /* if there already is a key by this name overwrite the value */
11229 if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key))) {
11230 buffer_copy_string(ds->value, value);
11237 return response_header_insert(srv, con, key, keylen, value, vallen);
11240 int http_response_redirect_to_directory(server *srv, connection *con) {
11247 if (con->conf.is_ssl) {
11248 buffer_copy_string(o, "https://");
11250 @@ -123,36 +123,36 @@
11252 sock_addr our_addr;
11253 socklen_t our_addr_len;
11256 our_addr_len = sizeof(our_addr);
11258 - if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
11260 + if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
11261 con->http_status = 500;
11264 log_error_write(srv, __FILE__, __LINE__, "ss",
11265 "can't get sockname", strerror(errno));
11275 /* Lookup name: secondly try to get hostname for bind address */
11276 switch(our_addr.plain.sa_family) {
11279 - if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
11280 - SA_LEN((const struct sockaddr *)&our_addr.ipv6),
11281 + if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
11282 + SA_LEN((const struct sockaddr *)&our_addr.ipv6),
11283 hbuf, sizeof(hbuf), NULL, 0, 0)) {
11286 char dst[INET6_ADDRSTRLEN];
11289 log_error_write(srv, __FILE__, __LINE__,
11290 "SSSS", "NOTICE: getnameinfo failed: ",
11291 strerror(errno), ", using ip-address instead");
11293 - buffer_append_string(o,
11294 - inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
11296 + buffer_append_string(o,
11297 + inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
11298 dst, sizeof(dst)));
11300 buffer_append_string(o, hbuf);
11301 @@ -164,7 +164,7 @@
11302 log_error_write(srv, __FILE__, __LINE__,
11303 "SdSS", "NOTICE: gethostbyaddr failed: ",
11304 h_errno, ", using ip-address instead");
11307 buffer_append_string(o, inet_ntoa(our_addr.ipv4.sin_addr));
11309 buffer_append_string(o, he->h_name);
11310 @@ -173,12 +173,12 @@
11312 log_error_write(srv, __FILE__, __LINE__,
11313 "S", "ERROR: unsupported address-type");
11320 - if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) ||
11322 + if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) ||
11323 (con->conf.is_ssl == 1 && srv->srvconf.port == 443))) {
11324 buffer_append_string(o, ":");
11325 buffer_append_long(o, srv->srvconf.port);
11326 @@ -190,46 +190,49 @@
11327 buffer_append_string(o, "?");
11328 buffer_append_string_buffer(o, con->uri.query);
11332 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(o));
11335 con->http_status = 301;
11336 - con->file_finished = 1;
11338 + con->send->is_closed = 1; /* no content */
11346 buffer * strftime_cache_get(server *srv, time_t last_mod) {
11351 for (i = 0; i < FILE_CACHE_MAX; i++) {
11352 /* found cache-entry */
11353 if (srv->mtime_cache[i].mtime == last_mod) return srv->mtime_cache[i].str;
11356 /* found empty slot */
11357 if (srv->mtime_cache[i].mtime == 0) break;
11361 if (i == FILE_CACHE_MAX) {
11366 srv->mtime_cache[i].mtime = last_mod;
11367 buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
11368 tm = gmtime(&(srv->mtime_cache[i].mtime));
11369 - srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
11370 + srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
11371 srv->mtime_cache[i].str->size - 1,
11372 "%a, %d %b %Y %H:%M:%S GMT", tm);
11373 srv->mtime_cache[i].str->used++;
11376 return srv->mtime_cache[i].str;
11380 int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) {
11381 + data_string *http_if_none_match;
11382 + data_string *http_if_modified_since;
11385 * 14.26 If-None-Match
11387 @@ -239,56 +242,63 @@
11388 * request. That is, if no entity tags match, then the server MUST NOT
11389 * return a 304 (Not Modified) response.
11393 + http_if_none_match = (data_string *)array_get_element(con->request.headers, "if-none-match");
11394 + http_if_modified_since = (data_string *)array_get_element(con->request.headers, "if-modified-since");
11396 /* last-modified handling */
11397 - if (con->request.http_if_none_match) {
11398 - if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
11399 - if (con->request.http_method == HTTP_METHOD_GET ||
11400 + if (http_if_none_match) {
11401 + if (etag_is_equal(con->physical.etag, BUF_STR(http_if_none_match->value))) {
11402 + if (con->request.http_method == HTTP_METHOD_GET ||
11403 con->request.http_method == HTTP_METHOD_HEAD) {
11406 /* check if etag + last-modified */
11407 - if (con->request.http_if_modified_since) {
11408 + if (http_if_modified_since) {
11412 - if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
11413 - used_len = strlen(con->request.http_if_modified_since);
11415 + if (NULL == (semicolon = strchr(BUF_STR(http_if_modified_since->value), ';'))) {
11416 + used_len = http_if_modified_since->value->used - 1;
11418 - used_len = semicolon - con->request.http_if_modified_since;
11419 + used_len = semicolon - BUF_STR(http_if_modified_since->value);
11422 - if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
11424 + if (0 == strncmp(BUF_STR(http_if_modified_since->value), mtime->ptr, used_len)) {
11425 con->http_status = 304;
11426 return HANDLER_FINISHED;
11428 +#ifdef HAVE_STRPTIME
11429 char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
11430 + time_t t_header, t_file;
11433 + /* check if we can safely copy the string */
11434 + if (used_len >= sizeof(buf)) {
11435 + TRACE("last-mod check failed as timestamp was too long: %s: %d, %d",
11436 + BUF_STR(http_if_modified_since->value),
11437 + used_len, sizeof(buf) - 1);
11439 - /* convert to timestamp */
11440 - if (used_len < sizeof(buf)) {
11441 - time_t t_header, t_file;
11444 - strncpy(buf, con->request.http_if_modified_since, used_len);
11445 - buf[used_len] = '\0';
11447 - strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
11448 - t_header = mktime(&tm);
11450 - strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
11451 - t_file = mktime(&tm);
11453 - if (t_file > t_header) {
11454 - con->http_status = 304;
11455 - return HANDLER_FINISHED;
11458 - log_error_write(srv, __FILE__, __LINE__, "ssdd",
11459 - "DEBUG: Last-Modified check failed as the received timestamp was too long:",
11460 - con->request.http_if_modified_since, used_len, sizeof(buf) - 1);
11462 con->http_status = 412;
11463 return HANDLER_FINISHED;
11467 + strncpy(buf, BUF_STR(http_if_modified_since->value), used_len);
11468 + buf[used_len] = '\0';
11470 + strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
11471 + t_header = mktime(&tm);
11473 + strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
11474 + t_file = mktime(&tm);
11476 + if (t_file > t_header) return HANDLER_GO_ON;
11478 + con->http_status = 304;
11479 + return HANDLER_FINISHED;
11481 + return HANDLER_GO_ON;
11485 con->http_status = 304;
11486 @@ -299,19 +309,44 @@
11487 return HANDLER_FINISHED;
11490 - } else if (con->request.http_if_modified_since) {
11491 + } else if (http_if_modified_since) {
11495 - if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
11496 - used_len = strlen(con->request.http_if_modified_since);
11498 + if (NULL == (semicolon = strchr(BUF_STR(http_if_modified_since->value), ';'))) {
11499 + used_len = http_if_modified_since->value->used - 1;
11501 - used_len = semicolon - con->request.http_if_modified_since;
11502 + used_len = semicolon - BUF_STR(http_if_modified_since->value);
11505 - if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
11507 + if (0 == strncmp(BUF_STR(http_if_modified_since->value), mtime->ptr, used_len)) {
11508 con->http_status = 304;
11509 return HANDLER_FINISHED;
11511 +#ifdef HAVE_STRPTIME
11512 + char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
11513 + time_t t_header, t_file;
11516 + /* convert to timestamp */
11517 + if (used_len >= sizeof(buf)) return HANDLER_GO_ON;
11519 + strncpy(buf, BUF_STR(http_if_modified_since->value), used_len);
11520 + buf[used_len] = '\0';
11522 + strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
11523 + t_header = mktime(&tm);
11525 + strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
11526 + t_file = mktime(&tm);
11528 + if (t_file > t_header) return HANDLER_GO_ON;
11530 + con->http_status = 304;
11531 + return HANDLER_FINISHED;
11533 + return HANDLER_GO_ON;
11538 --- ../lighttpd-1.4.11/src/http_auth.c 2006-02-01 13:02:52.000000000 +0200
11539 +++ lighttpd-1.5.0/src/http_auth.c 2006-09-07 00:57:05.000000000 +0300
11541 #include <string.h>
11544 -#include <unistd.h>
11547 #include "server.h"
11548 @@ -31,23 +30,15 @@
11549 #include "http_auth_digest.h"
11550 #include "stream.h"
11552 +#include "sys-strings.h"
11553 +#include "sys-files.h"
11556 # include <openssl/md5.h>
11563 -#include <security/pam_appl.h>
11564 -#include <security/pam_misc.h>
11566 -static struct pam_conv conv = {
11572 handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
11574 static const char base64_pad = '=';
11575 @@ -75,25 +66,25 @@
11576 unsigned char *result;
11581 size_t in_len = strlen(in);
11584 buffer_prepare_copy(out, in_len);
11587 result = (unsigned char *)out->ptr;
11591 /* run through the whole string, converting as we go */
11592 for (i = 0; i < in_len; i++) {
11596 if (ch == '\0') break;
11599 if (ch == base64_pad) break;
11602 ch = base64_reverse_table[ch];
11603 if (ch < 0) continue;
11608 result[j] = ch << 2;
11609 @@ -125,168 +116,168 @@
11621 static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *username, buffer *realm, buffer *password) {
11625 if (!username->used|| !realm->used) return -1;
11628 if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
11633 if (buffer_is_empty(p->conf.auth_htdigest_userfile)) return -1;
11636 if (0 != stream_open(&f, p->conf.auth_htdigest_userfile)) {
11637 log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", p->conf.auth_htdigest_userfile, "failed:", strerror(errno));
11647 while (f_line - f.start != f.size) {
11648 char *f_user, *f_pwd, *e, *f_realm;
11649 size_t u_len, pwd_len, r_len;
11659 - * user:realm:md5(user:realm:password)
11661 + * user:realm:md5(user:realm:password)
11665 if (NULL == (f_realm = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
11666 - log_error_write(srv, __FILE__, __LINE__, "sbs",
11667 - "parsed error in", p->conf.auth_htdigest_userfile,
11668 + log_error_write(srv, __FILE__, __LINE__, "sbs",
11669 + "parsed error in", p->conf.auth_htdigest_userfile,
11670 "expected 'username:realm:hashed password'");
11680 if (NULL == (f_pwd = memchr(f_realm + 1, ':', f.size - (f_realm + 1 - f.start)))) {
11681 - log_error_write(srv, __FILE__, __LINE__, "sbs",
11682 - "parsed error in", p->conf.auth_plain_userfile,
11683 + log_error_write(srv, __FILE__, __LINE__, "sbs",
11684 + "parsed error in", p->conf.auth_plain_userfile,
11685 "expected 'username:realm:hashed password'");
11695 /* get pointers to the fields */
11696 - u_len = f_realm - f_user;
11697 + u_len = f_realm - f_user;
11699 r_len = f_pwd - f_realm;
11703 if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
11704 pwd_len = e - f_pwd;
11706 pwd_len = f.size - (f_pwd - f.start);
11710 if (username->used - 1 == u_len &&
11711 (realm->used - 1 == r_len) &&
11712 (0 == strncmp(username->ptr, f_user, u_len)) &&
11713 (0 == strncmp(realm->ptr, f_realm, r_len))) {
11717 buffer_copy_string_len(password, f_pwd, pwd_len);
11734 } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD ||
11735 p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11741 auth_fn = (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) ? p->conf.auth_htpasswd_userfile : p->conf.auth_plain_userfile;
11744 if (buffer_is_empty(auth_fn)) return -1;
11747 if (0 != stream_open(&f, auth_fn)) {
11748 - log_error_write(srv, __FILE__, __LINE__, "sbss",
11749 + log_error_write(srv, __FILE__, __LINE__, "sbss",
11750 "opening plain-userfile", auth_fn, "failed:", strerror(errno));
11760 while (f_line - f.start != f.size) {
11761 char *f_user, *f_pwd, *e;
11762 size_t u_len, pwd_len;
11773 * user:crypted passwd
11777 if (NULL == (f_pwd = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
11778 - log_error_write(srv, __FILE__, __LINE__, "sbs",
11779 - "parsed error in", auth_fn,
11780 + log_error_write(srv, __FILE__, __LINE__, "sbs",
11781 + "parsed error in", auth_fn,
11782 "expected 'username:hashed password'");
11792 /* get pointers to the fields */
11793 - u_len = f_pwd - f_user;
11794 + u_len = f_pwd - f_user;
11798 if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
11799 pwd_len = e - f_pwd;
11801 pwd_len = f.size - (f_pwd - f.start);
11805 if (username->used - 1 == u_len &&
11806 (0 == strncmp(username->ptr, f_user, u_len))) {
11810 buffer_copy_string_len(password, f_pwd, pwd_len);
11827 } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
11837 @@ -296,7 +287,7 @@
11839 data_string *require;
11846 @@ -304,12 +295,12 @@
11847 /* search auth-directives for path */
11848 for (i = 0; i < p->conf.auth_require->used; i++) {
11849 if (p->conf.auth_require->data[i]->key->used == 0) continue;
11852 if (0 == strncmp(url, p->conf.auth_require->data[i]->key->ptr, p->conf.auth_require->data[i]->key->used - 1)) {
11858 if (i == p->conf.auth_require->used) {
11861 @@ -317,72 +308,72 @@
11862 req = ((data_array *)(p->conf.auth_require->data[i]))->value;
11864 require = (data_string *)array_get_element(req, "require");
11867 /* if we get here, the user we got a authed user */
11868 - if (0 == strcmp(require->value->ptr, "valid-user")) {
11869 + if (buffer_is_equal_string(require->value, CONST_STR_LEN("valid-user"))) {
11874 /* user=name1|group=name3|host=name4 */
11877 /* seperate the string by | */
11879 log_error_write(srv, __FILE__, __LINE__, "sb", "rules", require->value);
11884 username_len = username ? strlen(username) : 0;
11887 r = rules = require->value->ptr;
11892 const char *k, *v, *e;
11893 int k_len, v_len, r_len;
11896 e = strchr(r, '|');
11902 r_len = strlen(rules) - (r - rules);
11906 /* from r to r + r_len is a rule */
11909 if (0 == strncmp(r, "valid-user", r_len)) {
11910 - log_error_write(srv, __FILE__, __LINE__, "sb",
11911 + log_error_write(srv, __FILE__, __LINE__, "sb",
11912 "parsing the 'require' section in 'auth.require' failed: valid-user cannot be combined with other require rules",
11918 /* search for = in the rules */
11919 if (NULL == (eq = strchr(r, '='))) {
11920 - log_error_write(srv, __FILE__, __LINE__, "sb",
11921 - "parsing the 'require' section in 'auth.require' failed: a = is missing",
11922 + log_error_write(srv, __FILE__, __LINE__, "sb",
11923 + "parsing the 'require' section in 'auth.require' failed: a = is missing",
11929 /* = out of range */
11930 if (eq > r + r_len) {
11931 - log_error_write(srv, __FILE__, __LINE__, "sb",
11932 + log_error_write(srv, __FILE__, __LINE__, "sb",
11933 "parsing the 'require' section in 'auth.require' failed: = out of range",
11941 /* the part before the = is user|group|host */
11947 v_len = r_len - k_len - 1;
11951 if (0 == strncmp(k, "user", k_len)) {
11954 username_len == v_len &&
11955 0 == strncmp(username, v, v_len)) {
11957 @@ -404,19 +395,19 @@
11958 log_error_write(srv, __FILE__, __LINE__, "s", "unknown key");
11968 log_error_write(srv, __FILE__, __LINE__, "s", "nothing matched");
11979 * @param password password-string from the auth-backend
11980 * @param pw password-string from the client
11982 @@ -426,16 +417,16 @@
11985 if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
11990 - * user:realm:md5(user:realm:password)
11992 + * user:realm:md5(user:realm:password)
12002 MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1);
12003 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
12004 @@ -443,24 +434,24 @@
12005 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
12006 MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
12007 MD5_Final(HA1, &Md5Ctx);
12012 - if (0 == strcmp(password->ptr, a1)) {
12014 + if (buffer_is_equal_string(password, a1, strlen(a1))) {
12017 - } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
12019 + } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
12023 size_t salt_len = 0;
12029 * user:crypted password
12035 * CRYPT_STD_DES 2-character (Default)
12036 * CRYPT_EXT_DES 9-character
12037 @@ -478,7 +469,7 @@
12039 } else if (password->ptr[0] == '$' && password->ptr[2] == '$') {
12040 char *dollar = NULL;
12043 if (NULL == (dollar = strchr(password->ptr + 3, '$'))) {
12044 fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
12046 @@ -495,48 +486,21 @@
12047 strncpy(salt, password->ptr, salt_len);
12049 salt[salt_len] = '\0';
12052 crypted = crypt(pw, salt);
12054 - if (0 == strcmp(password->ptr, crypted)) {
12055 + if (buffer_is_equal_string(password, crypted, strlen(crypted))) {
12058 fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
12062 - } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
12063 - if (0 == strcmp(password->ptr, pw)) {
12066 - } else if (p->conf.auth_backend == AUTH_BACKEND_PAM) {
12068 - pam_handle_t *pamh=NULL;
12071 - retval = pam_start("lighttpd", username->ptr, &conv, &pamh);
12073 - if (retval == PAM_SUCCESS)
12074 - retval = pam_authenticate(pamh, 0); /* is user really user? */
12076 - if (retval == PAM_SUCCESS)
12077 - retval = pam_acct_mgmt(pamh, 0); /* permitted access? */
12079 - /* This is where we have been authorized or not. */
12081 - if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */
12083 - log_error_write(srv, __FILE__, __LINE__, "s", "failed to release authenticator");
12086 - if (retval == PAM_SUCCESS) {
12087 - log_error_write(srv, __FILE__, __LINE__, "s", "Authenticated");
12090 + } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
12091 + if (buffer_is_equal_string(password, pw, strlen(pw))) {
12094 - log_error_write(srv, __FILE__, __LINE__, "s", "Not Authenticated");
12097 - } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
12098 + } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
12101 LDAPMessage *lm, *first;
12102 @@ -544,45 +508,45 @@
12104 char *attrs[] = { LDAP_NO_ATTRS, NULL };
12108 /* for now we stay synchronous */
12113 * 1. connect anonymously (done in plugin init)
12114 * 2. get DN for uid = username
12115 * 3. auth against ldap server
12116 * 4. (optional) check a field
12126 * we have to protect us againt username which modifies out filter in
12131 for (i = 0; i < username->used - 1; i++) {
12132 char c = username->ptr[i];
12138 - log_error_write(srv, __FILE__, __LINE__, "sbd",
12140 + log_error_write(srv, __FILE__, __LINE__, "sbd",
12141 "ldap: invalid character (a-zA-Z0-9 allowed) in username:", username, i);
12154 buffer_copy_string_buffer(p->ldap_filter, p->conf.ldap_filter_pre);
12155 buffer_append_string_buffer(p->ldap_filter, username);
12156 buffer_append_string_buffer(p->ldap_filter, p->conf.ldap_filter_post);
12162 if (p->conf.ldap == NULL ||
12163 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))) {
12164 @@ -590,71 +554,71 @@
12166 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))) {
12168 - log_error_write(srv, __FILE__, __LINE__, "sssb",
12169 + log_error_write(srv, __FILE__, __LINE__, "sssb",
12170 "ldap:", ldap_err2string(ret), "filter:", p->ldap_filter);
12178 if (NULL == (first = ldap_first_entry(p->conf.ldap, lm))) {
12179 log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
12189 if (NULL == (dn = ldap_get_dn(p->conf.ldap, first))) {
12190 log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
12206 if (NULL == (ldap = ldap_init(p->conf.auth_ldap_hostname->ptr, LDAP_PORT))) {
12207 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
12212 ret = LDAP_VERSION3;
12213 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
12214 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
12217 ldap_unbind_s(ldap);
12224 if (p->conf.auth_ldap_starttls == 1) {
12225 if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(ldap, NULL, NULL))) {
12226 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
12229 ldap_unbind_s(ldap);
12238 if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(ldap, dn, pw))) {
12239 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
12242 ldap_unbind_s(ldap);
12250 ldap_unbind_s(ldap);
12253 /* everything worked, good, access granted */
12259 @@ -664,65 +628,65 @@
12260 int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
12261 buffer *username, *password;
12265 data_string *realm;
12268 realm = (data_string *)array_get_element(req, "realm");
12271 username = buffer_init();
12272 password = buffer_init();
12275 base64_decode(username, realm_str);
12278 /* r2 == user:password */
12279 if (NULL == (pw = strchr(username->ptr, ':'))) {
12280 buffer_free(username);
12283 log_error_write(srv, __FILE__, __LINE__, "sb", ": is missing in", username);
12293 username->used = pw - username->ptr;
12296 /* copy password to r1 */
12297 if (http_auth_get_password(srv, p, username, realm->value, password)) {
12298 buffer_free(username);
12299 buffer_free(password);
12302 log_error_write(srv, __FILE__, __LINE__, "s", "get_password failed");
12309 /* password doesn't match */
12310 if (http_auth_basic_password_compare(srv, p, req, username, realm->value, password, pw)) {
12311 log_error_write(srv, __FILE__, __LINE__, "sbb", "password doesn't match for", con->uri.path, username);
12314 buffer_free(username);
12315 buffer_free(password);
12322 /* value is our allow-rules */
12323 if (http_auth_match_rules(srv, p, url->ptr, username->ptr, NULL, NULL)) {
12324 buffer_free(username);
12325 buffer_free(password);
12328 log_error_write(srv, __FILE__, __LINE__, "s", "rules didn't match");
12335 /* remember the username */
12336 buffer_copy_string_buffer(p->auth_user, username);
12339 buffer_free(username);
12340 buffer_free(password);
12346 @@ -735,7 +699,7 @@
12347 int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
12355 @@ -745,18 +709,18 @@
12362 const char *m = NULL;
12364 buffer *password, *b, *username_buf, *realm_buf;
12375 /* init pointers */
12377 @@ -771,11 +735,11 @@
12380 { S("response=") },
12388 dkv[0].ptr = &username;
12389 dkv[1].ptr = &realm;
12390 dkv[2].ptr = &nonce;
12391 @@ -786,24 +750,24 @@
12393 dkv[8].ptr = &respons;
12400 for (i = 0; dkv[i].key; i++) {
12401 *(dkv[i].ptr) = NULL;
12407 if (p->conf.auth_backend != AUTH_BACKEND_HTDIGEST &&
12408 p->conf.auth_backend != AUTH_BACKEND_PLAIN) {
12409 - log_error_write(srv, __FILE__, __LINE__, "s",
12410 + log_error_write(srv, __FILE__, __LINE__, "s",
12411 "digest: unsupported backend (only htdigest or plain)");
12418 b = buffer_init_string(realm_str);
12421 /* parse credentials from client */
12422 for (c = b->ptr; *c; c++) {
12423 /* skip whitespaces */
12424 @@ -812,18 +776,18 @@
12426 for (i = 0; dkv[i].key; i++) {
12427 if ((0 == strncmp(c, dkv[i].key, dkv[i].key_len))) {
12428 - if ((c[dkv[i].key_len] == '"') &&
12429 + if ((c[dkv[i].key_len] == '"') &&
12430 (NULL != (e = strchr(c + dkv[i].key_len + 1, '"')))) {
12431 /* value with "..." */
12432 *(dkv[i].ptr) = c + dkv[i].key_len + 1;
12437 } else if (NULL != (e = strchr(c + dkv[i].key_len, ','))) {
12438 /* value without "...", terminated by ',' */
12439 *(dkv[i].ptr) = c + dkv[i].key_len;
12445 /* value without "...", terminated by EOL */
12446 @@ -833,7 +797,7 @@
12452 if (p->conf.auth_debug > 1) {
12453 log_error_write(srv, __FILE__, __LINE__, "ss", "username", username);
12454 log_error_write(srv, __FILE__, __LINE__, "ss", "realm", realm);
12455 @@ -845,22 +809,22 @@
12456 log_error_write(srv, __FILE__, __LINE__, "ss", "nc", nc);
12457 log_error_write(srv, __FILE__, __LINE__, "ss", "response", respons);
12461 /* check if everything is transmitted */
12467 (qop && (!nc || !cnonce)) ||
12469 /* missing field */
12471 - log_error_write(srv, __FILE__, __LINE__, "s",
12473 + log_error_write(srv, __FILE__, __LINE__, "s",
12474 "digest: missing field");
12478 - m = get_http_method_name(con->request.http_method);
12479 + m = get_http_method_name(con->request.http_method);
12481 /* password-string == HA1 */
12482 password = buffer_init();
12483 @@ -873,10 +837,10 @@
12484 buffer_free(realm_buf);
12489 buffer_free(username_buf);
12490 buffer_free(realm_buf);
12493 if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
12494 /* generate password from plain-text */
12496 @@ -890,16 +854,16 @@
12498 /* transform the 32-byte-hex-md5 to a 16-byte-md5 */
12499 for (i = 0; i < HASHLEN; i++) {
12500 - HA1[i] = hex2int(password->ptr[i*2]) << 4;
12501 - HA1[i] |= hex2int(password->ptr[i*2+1]);
12502 + HA1[i] = hex2int(password->ptr[i*2]) << 4;
12503 + HA1[i] |= hex2int(password->ptr[i*2+1]);
12506 /* we already check that above */
12511 buffer_free(password);
12515 strcasecmp(algorithm, "md5-sess") == 0) {
12517 @@ -910,9 +874,9 @@
12518 MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
12519 MD5_Final(HA1, &Md5Ctx);
12526 /* calculate H(A2) */
12528 MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m));
12529 @@ -924,7 +888,7 @@
12531 MD5_Final(HA2, &Md5Ctx);
12532 CvtHex(HA2, HA2Hex);
12535 /* calculate response */
12537 MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
12538 @@ -942,39 +906,39 @@
12539 MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
12540 MD5_Final(RespHash, &Md5Ctx);
12541 CvtHex(RespHash, a2);
12544 if (0 != strcmp(a2, respons)) {
12545 /* digest not ok */
12548 if (p->conf.auth_debug) {
12549 - log_error_write(srv, __FILE__, __LINE__, "sss",
12550 + log_error_write(srv, __FILE__, __LINE__, "sss",
12551 "digest: digest mismatch", a2, respons);
12554 - log_error_write(srv, __FILE__, __LINE__, "sss",
12556 + log_error_write(srv, __FILE__, __LINE__, "sss",
12557 "digest: auth failed for", username, "wrong password");
12565 /* value is our allow-rules */
12566 if (http_auth_match_rules(srv, p, url->ptr, username, NULL, NULL)) {
12569 - log_error_write(srv, __FILE__, __LINE__, "s",
12571 + log_error_write(srv, __FILE__, __LINE__, "s",
12572 "digest: rules did match");
12579 /* remember the username */
12580 buffer_copy_string(p->auth_user, username);
12586 if (p->conf.auth_debug) {
12587 - log_error_write(srv, __FILE__, __LINE__, "s",
12588 + log_error_write(srv, __FILE__, __LINE__, "s",
12589 "digest: auth ok");
12592 @@ -985,23 +949,23 @@
12600 /* generate shared-secret */
12602 MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1);
12603 MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
12606 /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
12607 ltostr(hh, srv->cur_ts);
12608 MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
12609 ltostr(hh, rand());
12610 MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
12613 MD5_Final(h, &Md5Ctx);
12621 --- ../lighttpd-1.4.11/src/http_auth.h 2005-08-14 17:12:31.000000000 +0300
12622 +++ lighttpd-1.5.0/src/http_auth.h 2006-07-16 00:26:04.000000000 +0300
12627 -typedef enum { AUTH_BACKEND_UNSET, AUTH_BACKEND_PLAIN,
12628 - AUTH_BACKEND_LDAP, AUTH_BACKEND_HTPASSWD,
12629 - AUTH_BACKEND_HTDIGEST, AUTH_BACKEND_PAM } auth_backend_t;
12631 + AUTH_BACKEND_UNSET,
12632 + AUTH_BACKEND_PLAIN,
12633 + AUTH_BACKEND_LDAP,
12634 + AUTH_BACKEND_HTPASSWD,
12635 + AUTH_BACKEND_HTDIGEST
12640 array *auth_require;
12643 buffer *auth_plain_groupfile;
12644 buffer *auth_plain_userfile;
12647 buffer *auth_htdigest_userfile;
12648 buffer *auth_htpasswd_userfile;
12651 buffer *auth_backend_conf;
12654 buffer *auth_ldap_hostname;
12655 buffer *auth_ldap_basedn;
12656 buffer *auth_ldap_binddn;
12657 @@ -32,15 +36,15 @@
12658 buffer *auth_ldap_filter;
12659 buffer *auth_ldap_cafile;
12660 unsigned short auth_ldap_starttls;
12663 unsigned short auth_debug;
12667 auth_backend_t auth_backend;
12674 buffer *ldap_filter_pre;
12675 buffer *ldap_filter_post;
12677 @@ -49,15 +53,15 @@
12686 buffer *ldap_filter;
12690 mod_auth_plugin_config **config_storage;
12693 mod_auth_plugin_config conf; /* this is only used as long as no handler_ctx is setup */
12694 } mod_auth_plugin_data;
12696 --- ../lighttpd-1.4.11/src/http_auth_digest.h 2006-01-05 00:54:01.000000000 +0200
12697 +++ lighttpd-1.5.0/src/http_auth_digest.h 2006-07-16 00:26:04.000000000 +0300
12707 --- ../lighttpd-1.4.11/src/http_chunk.c 2005-08-11 01:26:50.000000000 +0300
12708 +++ lighttpd-1.5.0/src/http_chunk.c 1970-01-01 03:00:00.000000000 +0300
12711 - * the HTTP chunk-API
12716 -#include <sys/types.h>
12717 -#include <sys/stat.h>
12719 -#include <stdlib.h>
12720 -#include <fcntl.h>
12721 -#include <unistd.h>
12723 -#include <stdio.h>
12724 -#include <errno.h>
12725 -#include <string.h>
12727 -#include "server.h"
12728 -#include "chunk.h"
12729 -#include "http_chunk.h"
12732 -static int http_chunk_append_len(server *srv, connection *con, size_t len) {
12733 - size_t i, olen = len, j;
12736 - b = srv->tmp_chunk_len;
12739 - buffer_copy_string(b, "0");
12741 - for (i = 0; i < 8 && len; i++) {
12745 - /* i is the number of hex digits we have */
12746 - buffer_prepare_copy(b, i + 1);
12748 - for (j = i-1, len = olen; j+1 > 0; j--) {
12749 - b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
12753 - b->ptr[b->used++] = '\0';
12756 - buffer_append_string(b, "\r\n");
12757 - chunkqueue_append_buffer(con->write_queue, b);
12763 -int http_chunk_append_file(server *srv, connection *con, buffer *fn, off_t offset, off_t len) {
12766 - if (!con) return -1;
12768 - cq = con->write_queue;
12770 - if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
12771 - http_chunk_append_len(srv, con, len);
12774 - chunkqueue_append_file(cq, fn, offset, len);
12776 - if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && len > 0) {
12777 - chunkqueue_append_mem(cq, "\r\n", 2 + 1);
12783 -int http_chunk_append_buffer(server *srv, connection *con, buffer *mem) {
12786 - if (!con) return -1;
12788 - cq = con->write_queue;
12790 - if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
12791 - http_chunk_append_len(srv, con, mem->used - 1);
12794 - chunkqueue_append_buffer(cq, mem);
12796 - if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && mem->used > 0) {
12797 - chunkqueue_append_mem(cq, "\r\n", 2 + 1);
12803 -int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len) {
12806 - if (!con) return -1;
12808 - cq = con->write_queue;
12811 - if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
12812 - http_chunk_append_len(srv, con, 0);
12813 - chunkqueue_append_mem(cq, "\r\n", 2 + 1);
12815 - chunkqueue_append_mem(cq, "", 1);
12820 - if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
12821 - http_chunk_append_len(srv, con, len - 1);
12824 - chunkqueue_append_mem(cq, mem, len);
12826 - if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
12827 - chunkqueue_append_mem(cq, "\r\n", 2 + 1);
12834 -off_t http_chunkqueue_length(server *srv, connection *con) {
12836 - log_error_write(srv, __FILE__, __LINE__, "s", "connection is NULL!!");
12841 - return chunkqueue_length(con->write_queue);
12843 --- ../lighttpd-1.4.11/src/http_chunk.h 2005-08-11 01:26:50.000000000 +0300
12844 +++ lighttpd-1.5.0/src/http_chunk.h 1970-01-01 03:00:00.000000000 +0300
12846 -#ifndef _HTTP_CHUNK_H_
12847 -#define _HTTP_CHUNK_H_
12849 -#include "server.h"
12850 -#include <sys/types.h>
12852 -int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len);
12853 -int http_chunk_append_buffer(server *srv, connection *con, buffer *mem);
12854 -int http_chunk_append_file(server *srv, connection *con, buffer *fn, off_t offset, off_t len);
12855 -off_t http_chunkqueue_length(server *srv, connection *con);
12858 --- ../lighttpd-1.4.11/src/http_parser.h 1970-01-01 03:00:00.000000000 +0300
12859 +++ lighttpd-1.5.0/src/http_parser.h 2006-09-07 00:57:05.000000000 +0300
12861 +#ifndef _HTTP_PARSER_H_
12862 +#define _HTTP_PARSER_H_
12872 --- ../lighttpd-1.4.11/src/http_req.c 1970-01-01 03:00:00.000000000 +0300
12873 +++ lighttpd-1.5.0/src/http_req.c 2006-09-07 00:57:05.000000000 +0300
12875 +#include <string.h>
12876 +#include <stdlib.h>
12877 +#include <stdio.h>
12878 +#include <assert.h>
12881 +#include "http_req.h"
12882 +#include "http_req_parser.h"
12884 +/* declare prototypes for the parser */
12885 +void *http_req_parserAlloc(void *(*mallocProc)(size_t));
12886 +void http_req_parserFree(void *p, void (*freeProc)(void*));
12887 +void http_req_parserTrace(FILE *TraceFILE, char *zTracePrompt);
12888 +void http_req_parser(void *, int, buffer *, http_req_ctx_t *);
12893 + chunk *c; /* current chunk in the chunkqueue */
12894 + size_t offset; /* current offset in current chunk */
12897 + size_t lookup_offset;
12899 + int last_token_id;
12902 + int is_statusline;
12903 +} http_req_tokenizer_t;
12905 +http_req *http_request_init(void) {
12906 + http_req *req = calloc(1, sizeof(*req));
12908 + req->uri_raw = buffer_init();
12909 + req->headers = array_init();
12914 +void http_request_reset(http_req *req) {
12915 + if (!req) return;
12917 + buffer_reset(req->uri_raw);
12918 + array_reset(req->headers);
12922 +void http_request_free(http_req *req) {
12923 + if (!req) return;
12925 + buffer_free(req->uri_raw);
12926 + array_free(req->headers);
12931 +static int http_req_get_next_char(http_req_tokenizer_t *t, unsigned char *c) {
12932 + if (t->c->mem->used == 0) {
12933 + TRACE("chunk-len: %zd", t->c->mem->used);
12936 + if (t->offset == t->c->mem->used - 1) {
12937 + /* end of chunk, open next chunk */
12939 + if (!t->c->next) return -1;
12941 + t->c = t->c->next;
12942 + /* skip empty chunks */
12943 + while (t->c && t->c->mem->used == 0) t->c = t->c->next;
12944 + if (!t->c) return -1;
12949 + *c = t->c->mem->ptr[t->offset++];
12951 + t->lookup_offset = t->offset;
12952 + t->lookup_c = t->c;
12955 + fprintf(stderr, "%s.%d: get: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->offset - 1);
12961 +static int http_req_lookup_next_char(http_req_tokenizer_t *t, unsigned char *c) {
12962 + if (t->lookup_c->mem->used == 0) {
12963 + TRACE("chunk-len: %zd", t->lookup_c->mem->used);
12965 + if (t->lookup_offset == t->lookup_c->mem->used - 1) {
12966 + /* end of chunk, open next chunk */
12968 + if (!t->lookup_c->next) return -1;
12970 + t->lookup_c = t->lookup_c->next;
12972 + /* skip empty chunks */
12973 + while (t->lookup_c && t->lookup_c->mem->used == 0) t->lookup_c = t->lookup_c->next;
12974 + if (!t->lookup_c) return -1;
12976 + t->lookup_offset = 0;
12979 + *c = t->lookup_c->mem->ptr[t->lookup_offset++];
12981 + fprintf(stderr, "%s.%d: lookup: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->lookup_offset - 1);
12988 +static int http_req_tokenizer(
12989 + http_req_tokenizer_t *t,
12996 + /* push the token to the parser */
12998 + while (tid == 0 && 0 == http_req_get_next_char(t, &c)) {
13008 + if (t->last_token_id == TK_CRLF) {
13009 + /* WS as the start of a line */
13014 + /* ignore the rest of the WS-chars */
13017 + if (0 != http_req_lookup_next_char(t, &c)) return -1;
13022 + t->c = t->lookup_c;
13023 + t->offset = t->lookup_offset;
13025 + t->is_statusline = 0;
13028 + fprintf(stderr, "%s.%d: CR with out LF\r\n", __FILE__, __LINE__);
13035 + t->is_statusline = 0;
13040 + while (c >= 32 && c != 127 && c != 255) {
13041 + if (t->is_statusline) {
13042 + if (c == 32) break; /* the space is a splitter in the statusline */
13045 + if (c == ':') break; /* the : is the splitter between key and value */
13046 + if (c == ' ') break; /* no spaces in keys */
13049 + if (0 != http_req_lookup_next_char(t, &c)) return -1;
13052 + if (t->c == t->lookup_c &&
13053 + t->offset == t->lookup_offset + 1) {
13055 + fprintf(stderr, "%s.%d: invalid char in string\n", __FILE__, __LINE__);
13061 + /* the lookup points to the first invalid char */
13062 + t->lookup_offset--;
13064 + /* no overlapping string */
13065 + if (t->c == t->lookup_c) {
13066 + buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->lookup_offset - t->offset + 1);
13068 + /* first chunk */
13069 + buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->c->mem->used - t->offset);
13071 + /* chunks in the middle */
13072 + for (t->c = t->c->next; t->c != t->lookup_c; t->c = t->c->next) {
13073 + buffer_append_string_buffer(token, t->c->mem);
13074 + t->offset = t->c->mem->used - 1;
13078 + buffer_append_string_len(token, t->c->mem->ptr, t->lookup_offset);
13081 + t->offset = t->lookup_offset;
13096 +parse_status_t http_request_parse_cq(chunkqueue *cq, http_req *req) {
13097 + http_req_tokenizer_t t;
13098 + void *pParser = NULL;
13099 + int token_id = 0;
13100 + buffer *token = NULL;
13101 + http_req_ctx_t context;
13102 + parse_status_t ret = PARSE_UNSET;
13106 + t.offset = t.c->offset;
13108 + t.is_statusline = 1;
13109 + t.last_token_id = 0;
13112 + context.errmsg = buffer_init();
13113 + context.req = req;
13115 + pParser = http_req_parserAlloc( malloc );
13116 + token = buffer_init();
13119 + http_req_parserTrace(stderr, "http-request: ");
13122 + while((1 == http_req_tokenizer(&t, &token_id, token)) && context.ok) {
13123 + http_req_parser(pParser, token_id, token, &context);
13125 + token = buffer_init();
13127 + /* CRLF CRLF ... the header end sequence */
13128 + if (t.last_token_id == TK_CRLF &&
13129 + token_id == TK_CRLF) break;
13131 + t.last_token_id = token_id;
13134 + /* oops, the parser failed */
13135 + if (context.ok == 0) {
13136 + ret = PARSE_ERROR;
13138 + if (!buffer_is_empty(context.errmsg)) {
13139 + TRACE("parsing failed: %s", BUF_STR(context.errmsg));
13141 + TRACE("%s", "parsing failed ... (no error-msg)");
13145 + http_req_parser(pParser, 0, token, &context);
13146 + http_req_parserFree(pParser, free);
13148 + if (context.ok == 0) {
13149 + /* we are missing the some tokens */
13151 + if (!buffer_is_empty(context.errmsg)) {
13152 + TRACE("parsing failed: %s", BUF_STR(context.errmsg));
13155 + if (ret == PARSE_UNSET) {
13156 + ret = buffer_is_empty(context.errmsg) ? PARSE_NEED_MORE : PARSE_ERROR;
13161 + for (c = cq->first; c != t.c; c = c->next) {
13162 + c->offset = c->mem->used - 1;
13165 + c->offset = t.offset;
13167 + ret = PARSE_SUCCESS;
13170 + buffer_free(token);
13171 + buffer_free(context.errmsg);
13176 --- ../lighttpd-1.4.11/src/http_req.h 1970-01-01 03:00:00.000000000 +0300
13177 +++ lighttpd-1.5.0/src/http_req.h 2006-09-07 00:57:05.000000000 +0300
13179 +#ifndef _HTTP_REQ_H_
13180 +#define _HTTP_REQ_H_
13182 +#include "array.h"
13183 +#include "chunk.h"
13184 +#include "http_parser.h"
13187 + int protocol; /* http/1.0, http/1.1 */
13188 + int method; /* e.g. GET */
13189 + buffer *uri_raw; /* e.g. /foobar/ */
13200 +http_req *http_request_init(void);
13201 +void http_request_free(http_req *req);
13202 +void http_request_reset(http_req *req);
13204 +parse_status_t http_request_parse_cq(chunkqueue *cq, http_req *http_request);
13207 --- ../lighttpd-1.4.11/src/http_req_parser.c 1970-01-01 03:00:00.000000000 +0300
13208 +++ lighttpd-1.5.0/src/http_req_parser.c 2006-09-07 01:02:19.000000000 +0300
13210 +/* Driver template for the LEMON parser generator.
13211 +** The author disclaims copyright to this source code.
13213 +/* First off, code is include which follows the "include" declaration
13214 +** in the input file. */
13215 +#include <stdio.h>
13216 +#line 6 "./http_req_parser.y"
13218 +#include <assert.h>
13219 +#include <string.h>
13220 +#include "http_req.h"
13221 +#include "keyvalue.h"
13222 +#include "array.h"
13225 +#line 17 "http_req_parser.c"
13226 +/* Next is all token values, in a form suitable for use by makeheaders.
13227 +** This section will be null unless lemon is run with the -m switch.
13230 +** These constants (all generated automatically by the parser generator)
13231 +** specify the various kinds of tokens (terminals) that the parser
13234 +** Each symbol here is a terminal symbol in the grammar.
13236 +/* Make sure the INTERFACE macro is defined.
13239 +# define INTERFACE 1
13241 +/* The next thing included is series of defines which control
13242 +** various aspects of the generated parser.
13243 +** YYCODETYPE is the data type used for storing terminal
13244 +** and nonterminal numbers. "unsigned char" is
13245 +** used if there are fewer than 250 terminals
13246 +** and nonterminals. "int" is used otherwise.
13247 +** YYNOCODE is a number of type YYCODETYPE which corresponds
13248 +** to no legal terminal or nonterminal number. This
13249 +** number is used to fill in empty slots of the hash
13251 +** YYFALLBACK If defined, this indicates that one or more tokens
13252 +** have fall-back values which should be used if the
13253 +** original value of the token will not parse.
13254 +** YYACTIONTYPE is the data type used for storing terminal
13255 +** and nonterminal numbers. "unsigned char" is
13256 +** used if there are fewer than 250 rules and
13257 +** states combined. "int" is used otherwise.
13258 +** http_req_parserTOKENTYPE is the data type used for minor tokens given
13259 +** directly to the parser from the tokenizer.
13260 +** YYMINORTYPE is the data type used for all minor tokens.
13261 +** This is typically a union of many types, one of
13262 +** which is http_req_parserTOKENTYPE. The entry in the union
13263 +** for base tokens is called "yy0".
13264 +** YYSTACKDEPTH is the maximum depth of the parser's stack.
13265 +** http_req_parserARG_SDECL A static variable declaration for the %extra_argument
13266 +** http_req_parserARG_PDECL A parameter declaration for the %extra_argument
13267 +** http_req_parserARG_STORE Code to store %extra_argument into yypParser
13268 +** http_req_parserARG_FETCH Code to extract %extra_argument from yypParser
13269 +** YYNSTATE the combined number of states.
13270 +** YYNRULE the number of rules in the grammar
13271 +** YYERRORSYMBOL is the code number of the error symbol. If not
13272 +** defined, then do no error processing.
13275 +#define YYCODETYPE unsigned char
13276 +#define YYNOCODE 13
13277 +#define YYACTIONTYPE unsigned char
13278 +#define http_req_parserTOKENTYPE buffer *
13280 + http_req_parserTOKENTYPE yy0;
13283 + http_method_t yy8;
13284 + data_string * yy15;
13286 + http_version_t yy21;
13289 +#define YYSTACKDEPTH 100
13290 +#define http_req_parserARG_SDECL http_req_ctx_t *ctx;
13291 +#define http_req_parserARG_PDECL ,http_req_ctx_t *ctx
13292 +#define http_req_parserARG_FETCH http_req_ctx_t *ctx = yypParser->ctx
13293 +#define http_req_parserARG_STORE yypParser->ctx = ctx
13294 +#define YYNSTATE 20
13295 +#define YYNRULE 10
13296 +#define YYERRORSYMBOL 5
13297 +#define YYERRSYMDT yy25
13298 +#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
13299 +#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
13300 +#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
13302 +/* Next are that tables used to determine what action to take based on the
13303 +** current state and lookahead token. These tables are used to implement
13304 +** functions that take a state number and lookahead value and return an
13305 +** action integer.
13307 +** Suppose the action integer is N. Then the action is determined as
13310 +** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
13311 +** token onto the stack and goto state N.
13313 +** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
13315 +** N == YYNSTATE+YYNRULE A syntax error has occurred.
13317 +** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
13319 +** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
13320 +** slots in the yy_action[] table.
13322 +** The action table is constructed as a single large table named yy_action[].
13323 +** Given state S and lookahead X, the action is computed as
13325 +** yy_action[ yy_shift_ofst[S] + X ]
13327 +** If the index value yy_shift_ofst[S]+X is out of range or if the value
13328 +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
13329 +** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
13330 +** and that yy_default[S] should be used instead.
13332 +** The formula above is for computing the action when the lookahead is
13333 +** a terminal symbol. If the lookahead is a non-terminal (as occurs after
13334 +** a reduce action) then the yy_reduce_ofst[] array is used in place of
13335 +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
13336 +** YY_SHIFT_USE_DFLT.
13338 +** The following are the tables generated in this section:
13340 +** yy_action[] A single table containing all actions.
13341 +** yy_lookahead[] A table containing the lookahead for each entry in
13342 +** yy_action. Used to detect hash collisions.
13343 +** yy_shift_ofst[] For each state, the offset into yy_action for
13344 +** shifting terminals.
13345 +** yy_reduce_ofst[] For each state, the offset into yy_action for
13346 +** shifting non-terminals after a reduce.
13347 +** yy_default[] Default action for each state.
13349 +static YYACTIONTYPE yy_action[] = {
13350 + /* 0 */ 1, 31, 8, 16, 5, 17, 8, 6, 12, 11,
13351 + /* 10 */ 19, 2, 18, 7, 3, 4, 20, 9, 24, 13,
13352 + /* 20 */ 24, 12, 14, 10, 21, 23, 15, 22,
13354 +static YYCODETYPE yy_lookahead[] = {
13355 + /* 0 */ 7, 8, 1, 2, 9, 10, 1, 2, 1, 2,
13356 + /* 10 */ 1, 1, 1, 10, 6, 2, 0, 3, 12, 2,
13357 + /* 20 */ 12, 1, 4, 11, 0, 2, 11, 1,
13359 +#define YY_SHIFT_USE_DFLT (-1)
13360 +static signed char yy_shift_ofst[] = {
13361 + /* 0 */ 9, 10, 11, 13, 1, 5, 16, -1, 14, 7,
13362 + /* 10 */ -1, -1, 17, 18, 20, -1, 24, -1, 23, 26,
13364 +#define YY_REDUCE_USE_DFLT (-8)
13365 +static signed char yy_reduce_ofst[] = {
13366 + /* 0 */ -7, -8, 8, -8, -5, 3, -8, -8, -8, 12,
13367 + /* 10 */ -8, -8, -8, -8, 15, -8, -8, -8, -8, -8,
13369 +static YYACTIONTYPE yy_default[] = {
13370 + /* 0 */ 30, 30, 30, 30, 30, 30, 30, 24, 30, 30,
13371 + /* 10 */ 26, 27, 30, 29, 30, 28, 30, 25, 30, 30,
13373 +#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
13375 +/* The next table maps tokens into fallback tokens. If a construct
13376 +** like the following:
13378 +** %fallback ID X Y Z.
13380 +** appears in the grammer, then ID becomes a fallback token for X, Y,
13381 +** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
13382 +** but it does not parse, the type of the token is changed to ID and
13383 +** the parse is retried before an error is thrown.
13386 +static const YYCODETYPE yyFallback[] = {
13388 +#endif /* YYFALLBACK */
13390 +/* The following structure represents a single element of the
13391 +** parser's stack. Information stored includes:
13393 +** + The state number for the parser at this level of the stack.
13395 +** + The value of the token stored at this level of the stack.
13396 +** (In other words, the "major" token.)
13398 +** + The semantic value stored at this level of the stack. This is
13399 +** the information used by the action routines in the grammar.
13400 +** It is sometimes called the "minor" token.
13402 +struct yyStackEntry {
13403 + int stateno; /* The state-number */
13404 + int major; /* The major token value. This is the code
13405 + ** number for the token at this stack level */
13406 + YYMINORTYPE minor; /* The user-supplied minor token value. This
13407 + ** is the value of the token */
13409 +typedef struct yyStackEntry yyStackEntry;
13411 +/* The state of the parser is completely contained in an instance of
13412 +** the following structure */
13414 + int yyidx; /* Index of top element in stack */
13415 + int yyerrcnt; /* Shifts left before out of the error */
13416 + http_req_parserARG_SDECL /* A place to hold %extra_argument */
13417 + yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
13419 +typedef struct yyParser yyParser;
13422 +#include <stdio.h>
13423 +static FILE *yyTraceFILE = 0;
13424 +static char *yyTracePrompt = 0;
13425 +#endif /* NDEBUG */
13429 +** Turn parser tracing on by giving a stream to which to write the trace
13430 +** and a prompt to preface each trace message. Tracing is turned off
13431 +** by making either argument NULL
13435 +** <li> A FILE* to which trace output should be written.
13436 +** If NULL, then tracing is turned off.
13437 +** <li> A prefix string written at the beginning of every
13438 +** line of trace output. If NULL, then tracing is
13445 +void http_req_parserTrace(FILE *TraceFILE, char *zTracePrompt){
13446 + yyTraceFILE = TraceFILE;
13447 + yyTracePrompt = zTracePrompt;
13448 + if( yyTraceFILE==0 ) yyTracePrompt = 0;
13449 + else if( yyTracePrompt==0 ) yyTraceFILE = 0;
13451 +#endif /* NDEBUG */
13454 +/* For tracing shifts, the names of all terminals and nonterminals
13455 +** are required. The following table supplies these names */
13456 +static const char *yyTokenName[] = {
13457 + "$", "STRING", "CRLF", "COLON",
13458 + "TAB", "error", "protocol", "method",
13459 + "request_hdr", "headers", "header", "multiline",
13461 +#endif /* NDEBUG */
13464 +/* For tracing reduce actions, the names of all rules are required.
13466 +static const char *yyRuleName[] = {
13467 + /* 0 */ "request_hdr ::= method STRING protocol CRLF headers CRLF",
13468 + /* 1 */ "request_hdr ::= method STRING protocol CRLF CRLF",
13469 + /* 2 */ "method ::= STRING",
13470 + /* 3 */ "protocol ::= STRING",
13471 + /* 4 */ "headers ::= headers header",
13472 + /* 5 */ "headers ::= header",
13473 + /* 6 */ "header ::= STRING COLON multiline",
13474 + /* 7 */ "header ::= STRING COLON CRLF",
13475 + /* 8 */ "multiline ::= STRING CRLF TAB multiline",
13476 + /* 9 */ "multiline ::= STRING CRLF",
13478 +#endif /* NDEBUG */
13481 +** This function returns the symbolic name associated with a token
13484 +const char *http_req_parserTokenName(int tokenType){
13486 + if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
13487 + return yyTokenName[tokenType];
13489 + return "Unknown";
13497 +** This function allocates a new parser.
13498 +** The only argument is a pointer to a function which works like
13502 +** A pointer to the function used to allocate memory.
13505 +** A pointer to a parser. This pointer is used in subsequent calls
13506 +** to http_req_parser and http_req_parserFree.
13508 +void *http_req_parserAlloc(void *(*mallocProc)(size_t)){
13509 + yyParser *pParser;
13510 + pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
13512 + pParser->yyidx = -1;
13517 +/* The following function deletes the value associated with a
13518 +** symbol. The symbol can be either a terminal or nonterminal.
13519 +** "yymajor" is the symbol code, and "yypminor" is a pointer to
13522 +static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
13523 + switch( yymajor ){
13524 + /* Here is inserted the actions which take place when a
13525 + ** terminal or non-terminal is destroyed. This can happen
13526 + ** when the symbol is popped from the stack during a
13527 + ** reduce or during error processing or when a parser is
13528 + ** being destroyed before it is finished parsing.
13530 + ** Note: during a reduce, the only symbols destroyed are those
13531 + ** which appear on the RHS of the rule, but which are not used
13532 + ** inside the C code.
13538 +#line 25 "./http_req_parser.y"
13539 +{ buffer_free((yypminor->yy0)); }
13540 +#line 331 "http_req_parser.c"
13542 + default: break; /* If no destructor action specified: do nothing */
13547 +** Pop the parser's stack once.
13549 +** If there is a destructor routine associated with the token which
13550 +** is popped from the stack, then call it.
13552 +** Return the major token number for the symbol popped.
13554 +static int yy_pop_parser_stack(yyParser *pParser){
13555 + YYCODETYPE yymajor;
13556 + yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
13558 + if( pParser->yyidx<0 ) return 0;
13560 + if( yyTraceFILE && pParser->yyidx>=0 ){
13561 + fprintf(yyTraceFILE,"%sPopping %s\n",
13563 + yyTokenName[yytos->major]);
13566 + yymajor = yytos->major;
13567 + yy_destructor( yymajor, &yytos->minor);
13568 + pParser->yyidx--;
13573 +** Deallocate and destroy a parser. Destructors are all called for
13574 +** all stack elements before shutting the parser down.
13578 +** <li> A pointer to the parser. This should be a pointer
13579 +** obtained from http_req_parserAlloc.
13580 +** <li> A pointer to a function used to reclaim memory obtained
13584 +void http_req_parserFree(
13585 + void *p, /* The parser to be deleted */
13586 + void (*freeProc)(void*) /* Function used to reclaim memory */
13588 + yyParser *pParser = (yyParser*)p;
13589 + if( pParser==0 ) return;
13590 + while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
13591 + (*freeProc)((void*)pParser);
13595 +** Find the appropriate action for a parser given the terminal
13596 +** look-ahead token iLookAhead.
13598 +** If the look-ahead token is YYNOCODE, then check to see if the action is
13599 +** independent of the look-ahead. If it is, return the action, otherwise
13600 +** return YY_NO_ACTION.
13602 +static int yy_find_shift_action(
13603 + yyParser *pParser, /* The parser */
13604 + int iLookAhead /* The look-ahead token */
13607 + int stateno = pParser->yystack[pParser->yyidx].stateno;
13609 + /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
13610 + i = yy_shift_ofst[stateno];
13611 + if( i==YY_SHIFT_USE_DFLT ){
13612 + return yy_default[stateno];
13614 + if( iLookAhead==YYNOCODE ){
13615 + return YY_NO_ACTION;
13618 + if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
13620 + int iFallback; /* Fallback token */
13621 + if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
13622 + && (iFallback = yyFallback[iLookAhead])!=0 ){
13624 + if( yyTraceFILE ){
13625 + fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
13626 + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
13629 + return yy_find_shift_action(pParser, iFallback);
13632 + return yy_default[stateno];
13634 + return yy_action[i];
13639 +** Find the appropriate action for a parser given the non-terminal
13640 +** look-ahead token iLookAhead.
13642 +** If the look-ahead token is YYNOCODE, then check to see if the action is
13643 +** independent of the look-ahead. If it is, return the action, otherwise
13644 +** return YY_NO_ACTION.
13646 +static int yy_find_reduce_action(
13647 + yyParser *pParser, /* The parser */
13648 + int iLookAhead /* The look-ahead token */
13651 + int stateno = pParser->yystack[pParser->yyidx].stateno;
13653 + i = yy_reduce_ofst[stateno];
13654 + if( i==YY_REDUCE_USE_DFLT ){
13655 + return yy_default[stateno];
13657 + if( iLookAhead==YYNOCODE ){
13658 + return YY_NO_ACTION;
13661 + if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
13662 + return yy_default[stateno];
13664 + return yy_action[i];
13669 +** Perform a shift action.
13671 +static void yy_shift(
13672 + yyParser *yypParser, /* The parser to be shifted */
13673 + int yyNewState, /* The new state to shift in */
13674 + int yyMajor, /* The major token to shift in */
13675 + YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */
13677 + yyStackEntry *yytos;
13678 + yypParser->yyidx++;
13679 + if( yypParser->yyidx>=YYSTACKDEPTH ){
13680 + http_req_parserARG_FETCH;
13681 + yypParser->yyidx--;
13683 + if( yyTraceFILE ){
13684 + fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
13687 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
13688 + /* Here code is inserted which will execute if the parser
13689 + ** stack every overflows */
13690 + http_req_parserARG_STORE; /* Suppress warning about unused %extra_argument var */
13693 + yytos = &yypParser->yystack[yypParser->yyidx];
13694 + yytos->stateno = yyNewState;
13695 + yytos->major = yyMajor;
13696 + yytos->minor = *yypMinor;
13698 + if( yyTraceFILE && yypParser->yyidx>0 ){
13700 + fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
13701 + fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
13702 + for(i=1; i<=yypParser->yyidx; i++)
13703 + fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
13704 + fprintf(yyTraceFILE,"\n");
13709 +/* The following table contains information about every rule that
13710 +** is used during the reduce.
13713 + YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
13714 + unsigned char nrhs; /* Number of right-hand side symbols in the rule */
13715 +} yyRuleInfo[] = {
13728 +static void yy_accept(yyParser*); /* Forward Declaration */
13731 +** Perform a reduce action and the shift that must immediately
13732 +** follow the reduce.
13734 +static void yy_reduce(
13735 + yyParser *yypParser, /* The parser */
13736 + int yyruleno /* Number of the rule by which to reduce */
13738 + int yygoto; /* The next state */
13739 + int yyact; /* The next action */
13740 + YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
13741 + yyStackEntry *yymsp; /* The top of the parser's stack */
13742 + int yysize; /* Amount to pop the stack */
13743 + http_req_parserARG_FETCH;
13744 + yymsp = &yypParser->yystack[yypParser->yyidx];
13746 + if( yyTraceFILE && yyruleno>=0
13747 + && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
13748 + fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
13749 + yyRuleName[yyruleno]);
13751 +#endif /* NDEBUG */
13753 + switch( yyruleno ){
13754 + /* Beginning here are the reduction cases. A typical example
13757 + ** #line <lineno> <grammarfile>
13758 + ** { ... } // User supplied code
13759 + ** #line <lineno> <thisfile>
13763 +#line 28 "./http_req_parser.y"
13765 + http_req *req = ctx->req;
13767 + req->method = yymsp[-5].minor.yy8;
13768 + req->protocol = yymsp[-3].minor.yy21;
13769 + buffer_copy_string_buffer(req->uri_raw, yymsp[-4].minor.yy0);
13770 + buffer_free(yymsp[-4].minor.yy0);
13772 + array_free(req->headers);
13774 + req->headers = yymsp[-1].minor.yy6;
13776 +#line 567 "http_req_parser.c"
13777 + yy_destructor(2,&yymsp[-2].minor);
13778 + yy_destructor(2,&yymsp[0].minor);
13781 +#line 41 "./http_req_parser.y"
13783 + http_req *req = ctx->req;
13785 + req->method = yymsp[-4].minor.yy8;
13786 + req->protocol = yymsp[-2].minor.yy21;
13787 + buffer_copy_string_buffer(req->uri_raw, yymsp[-3].minor.yy0);
13788 + buffer_free(yymsp[-3].minor.yy0);
13790 +#line 581 "http_req_parser.c"
13791 + yy_destructor(2,&yymsp[-1].minor);
13792 + yy_destructor(2,&yymsp[0].minor);
13795 +#line 51 "./http_req_parser.y"
13797 + yygotominor.yy8 = get_http_method_key(BUF_STR(yymsp[0].minor.yy0));
13799 + buffer_free(yymsp[0].minor.yy0);
13801 +#line 592 "http_req_parser.c"
13804 +#line 57 "./http_req_parser.y"
13806 + /* the protocol might be HTTP/1.0 or HTTP/1.1
13807 + * the version string is allowed to have leading zeros
13809 + yygotominor.yy21 = HTTP_VERSION_UNSET;
13811 + if (0 == strncmp(BUF_STR(yymsp[0].minor.yy0), "HTTP/", 5)) {
13812 + char *err = NULL;
13813 + /* is there a dot */
13814 + char *major, *minor;
13816 + major = BUF_STR(yymsp[0].minor.yy0) + 5;
13817 + minor = strchr(major, '.');
13820 + hi = strtol(major, &err, 10);
13822 + if (*err == '.' && *minor != '\0') {
13823 + lo = strtol(minor, &err, 10);
13824 + if (*err == '\0') {
13825 + if (hi == 1 && lo == 1) {
13826 + yygotominor.yy21 = HTTP_VERSION_1_1;
13827 + } else if (hi == 1 && lo == 0) {
13828 + yygotominor.yy21 = HTTP_VERSION_1_0;
13835 + buffer_free(yymsp[0].minor.yy0);
13837 +#line 628 "http_req_parser.c"
13840 +#line 90 "./http_req_parser.y"
13842 + yygotominor.yy6 = yymsp[-1].minor.yy6;
13844 + if (yymsp[0].minor.yy15) {
13845 + array_insert_unique(yygotominor.yy6, (data_unset *)yymsp[0].minor.yy15);
13848 +#line 639 "http_req_parser.c"
13851 +#line 98 "./http_req_parser.y"
13853 + if (yymsp[0].minor.yy15) {
13854 + yygotominor.yy6 = array_init();
13856 + array_insert_unique(yygotominor.yy6, (data_unset *)yymsp[0].minor.yy15);
13859 +#line 650 "http_req_parser.c"
13862 +#line 106 "./http_req_parser.y"
13864 + yygotominor.yy15 = data_string_init();
13866 + buffer_copy_string_buffer(yygotominor.yy15->key, yymsp[-2].minor.yy0);
13867 + buffer_copy_string_buffer(yygotominor.yy15->value, yymsp[0].minor.yy17);
13868 + buffer_free(yymsp[-2].minor.yy0);
13869 + buffer_free(yymsp[0].minor.yy17);
13871 +#line 662 "http_req_parser.c"
13872 + yy_destructor(3,&yymsp[-1].minor);
13875 +#line 115 "./http_req_parser.y"
13877 + /* ignore empty header fields */
13879 + yygotominor.yy15 = NULL;
13881 +#line 672 "http_req_parser.c"
13882 + yy_destructor(1,&yymsp[-2].minor);
13883 + yy_destructor(3,&yymsp[-1].minor);
13884 + yy_destructor(2,&yymsp[0].minor);
13887 +#line 121 "./http_req_parser.y"
13889 + buffer_append_string_buffer(yymsp[-3].minor.yy0, yymsp[0].minor.yy17);
13890 + yygotominor.yy17 = yymsp[-3].minor.yy0;
13892 + yymsp[-3].minor.yy0 = NULL;
13893 + buffer_free(yymsp[0].minor.yy17);
13895 +#line 686 "http_req_parser.c"
13896 + yy_destructor(2,&yymsp[-2].minor);
13897 + yy_destructor(4,&yymsp[-1].minor);
13900 +#line 130 "./http_req_parser.y"
13902 + yygotominor.yy17 = yymsp[-1].minor.yy0;
13904 + yymsp[-1].minor.yy0 = NULL;
13906 +#line 697 "http_req_parser.c"
13907 + yy_destructor(2,&yymsp[0].minor);
13910 + yygoto = yyRuleInfo[yyruleno].lhs;
13911 + yysize = yyRuleInfo[yyruleno].nrhs;
13912 + yypParser->yyidx -= yysize;
13913 + yyact = yy_find_reduce_action(yypParser,yygoto);
13914 + if( yyact < YYNSTATE ){
13915 + yy_shift(yypParser,yyact,yygoto,&yygotominor);
13916 + }else if( yyact == YYNSTATE + YYNRULE + 1 ){
13917 + yy_accept(yypParser);
13922 +** The following code executes when the parse fails
13924 +static void yy_parse_failed(
13925 + yyParser *yypParser /* The parser */
13927 + http_req_parserARG_FETCH;
13929 + if( yyTraceFILE ){
13930 + fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
13933 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
13934 + /* Here code is inserted which will be executed whenever the
13935 + ** parser fails */
13936 +#line 15 "./http_req_parser.y"
13940 +#line 731 "http_req_parser.c"
13941 + http_req_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
13945 +** The following code executes when a syntax error first occurs.
13947 +static void yy_syntax_error(
13948 + yyParser *yypParser, /* The parser */
13949 + int yymajor, /* The major type of the error token */
13950 + YYMINORTYPE yyminor /* The minor type of the error token */
13952 + http_req_parserARG_FETCH;
13953 +#define TOKEN (yyminor.yy0)
13954 + http_req_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
13958 +** The following is executed when the parser accepts
13960 +static void yy_accept(
13961 + yyParser *yypParser /* The parser */
13963 + http_req_parserARG_FETCH;
13965 + if( yyTraceFILE ){
13966 + fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
13969 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
13970 + /* Here code is inserted which will be executed whenever the
13971 + ** parser accepts */
13972 + http_req_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
13975 +/* The main parser program.
13976 +** The first argument is a pointer to a structure obtained from
13977 +** "http_req_parserAlloc" which describes the current state of the parser.
13978 +** The second argument is the major token number. The third is
13979 +** the minor token. The fourth optional argument is whatever the
13980 +** user wants (and specified in the grammar) and is available for
13981 +** use by the action routines.
13985 +** <li> A pointer to the parser (an opaque structure.)
13986 +** <li> The major token number.
13987 +** <li> The minor token number.
13988 +** <li> An option argument of a grammar-specified type.
13994 +void http_req_parser(
13995 + void *yyp, /* The parser */
13996 + int yymajor, /* The major token code number */
13997 + http_req_parserTOKENTYPE yyminor /* The value for the token */
13998 + http_req_parserARG_PDECL /* Optional %extra_argument parameter */
14000 + YYMINORTYPE yyminorunion;
14001 + int yyact; /* The parser action. */
14002 + int yyendofinput; /* True if we are at the end of input */
14003 + int yyerrorhit = 0; /* True if yymajor has invoked an error */
14004 + yyParser *yypParser; /* The parser */
14006 + /* (re)initialize the parser, if necessary */
14007 + yypParser = (yyParser*)yyp;
14008 + if( yypParser->yyidx<0 ){
14009 + if( yymajor==0 ) return;
14010 + yypParser->yyidx = 0;
14011 + yypParser->yyerrcnt = -1;
14012 + yypParser->yystack[0].stateno = 0;
14013 + yypParser->yystack[0].major = 0;
14015 + yyminorunion.yy0 = yyminor;
14016 + yyendofinput = (yymajor==0);
14017 + http_req_parserARG_STORE;
14020 + if( yyTraceFILE ){
14021 + fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
14026 + yyact = yy_find_shift_action(yypParser,yymajor);
14027 + if( yyact<YYNSTATE ){
14028 + yy_shift(yypParser,yyact,yymajor,&yyminorunion);
14029 + yypParser->yyerrcnt--;
14030 + if( yyendofinput && yypParser->yyidx>=0 ){
14033 + yymajor = YYNOCODE;
14035 + }else if( yyact < YYNSTATE + YYNRULE ){
14036 + yy_reduce(yypParser,yyact-YYNSTATE);
14037 + }else if( yyact == YY_ERROR_ACTION ){
14040 + if( yyTraceFILE ){
14041 + fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
14044 +#ifdef YYERRORSYMBOL
14045 + /* A syntax error has occurred.
14046 + ** The response to an error depends upon whether or not the
14047 + ** grammar defines an error token "ERROR".
14049 + ** This is what we do if the grammar does define ERROR:
14051 + ** * Call the %syntax_error function.
14053 + ** * Begin popping the stack until we enter a state where
14054 + ** it is legal to shift the error symbol, then shift
14055 + ** the error symbol.
14057 + ** * Set the error count to three.
14059 + ** * Begin accepting and shifting new tokens. No new error
14060 + ** processing will occur until three tokens have been
14061 + ** shifted successfully.
14064 + if( yypParser->yyerrcnt<0 ){
14065 + yy_syntax_error(yypParser,yymajor,yyminorunion);
14067 + yymx = yypParser->yystack[yypParser->yyidx].major;
14068 + if( yymx==YYERRORSYMBOL || yyerrorhit ){
14070 + if( yyTraceFILE ){
14071 + fprintf(yyTraceFILE,"%sDiscard input token %s\n",
14072 + yyTracePrompt,yyTokenName[yymajor]);
14075 + yy_destructor(yymajor,&yyminorunion);
14076 + yymajor = YYNOCODE;
14079 + yypParser->yyidx >= 0 &&
14080 + yymx != YYERRORSYMBOL &&
14081 + (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
14083 + yy_pop_parser_stack(yypParser);
14085 + if( yypParser->yyidx < 0 || yymajor==0 ){
14086 + yy_destructor(yymajor,&yyminorunion);
14087 + yy_parse_failed(yypParser);
14088 + yymajor = YYNOCODE;
14089 + }else if( yymx!=YYERRORSYMBOL ){
14091 + u2.YYERRSYMDT = 0;
14092 + yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
14095 + yypParser->yyerrcnt = 3;
14097 +#else /* YYERRORSYMBOL is not defined */
14098 + /* This is what we do if the grammar does not define ERROR:
14100 + ** * Report an error message, and throw away the input token.
14102 + ** * If the input token is $, then fail the parse.
14104 + ** As before, subsequent error messages are suppressed until
14105 + ** three input tokens have been successfully shifted.
14107 + if( yypParser->yyerrcnt<=0 ){
14108 + yy_syntax_error(yypParser,yymajor,yyminorunion);
14110 + yypParser->yyerrcnt = 3;
14111 + yy_destructor(yymajor,&yyminorunion);
14112 + if( yyendofinput ){
14113 + yy_parse_failed(yypParser);
14115 + yymajor = YYNOCODE;
14118 + yy_accept(yypParser);
14119 + yymajor = YYNOCODE;
14121 + }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
14124 --- ../lighttpd-1.4.11/src/http_req_parser.h 1970-01-01 03:00:00.000000000 +0300
14125 +++ lighttpd-1.5.0/src/http_req_parser.h 2006-09-07 01:02:19.000000000 +0300
14127 +#define TK_STRING 1
14129 +#define TK_COLON 3
14131 --- ../lighttpd-1.4.11/src/http_req_parser.y 1970-01-01 03:00:00.000000000 +0300
14132 +++ lighttpd-1.5.0/src/http_req_parser.y 2006-09-07 00:57:05.000000000 +0300
14135 +%token_type {buffer *}
14136 +%extra_argument {http_req_ctx_t *ctx}
14137 +%name http_req_parser
14140 +#include <assert.h>
14141 +#include <string.h>
14142 +#include "http_req.h"
14143 +#include "keyvalue.h"
14144 +#include "array.h"
14152 +%type protocol { http_version_t }
14153 +%type method { http_method_t }
14154 +%type request_hdr { http_req * }
14155 +%type headers { array * }
14156 +%type header { data_string * }
14157 +%type multiline { buffer * }
14158 +%token_destructor { buffer_free($$); }
14160 +/* GET ... HTTP/1.0 */
14161 +request_hdr ::= method(B) STRING(C) protocol(D) CRLF headers(HDR) CRLF . {
14162 + http_req *req = ctx->req;
14165 + req->protocol = D;
14166 + buffer_copy_string_buffer(req->uri_raw, C);
14169 + array_free(req->headers);
14171 + req->headers = HDR;
14174 +request_hdr ::= method(B) STRING(C) protocol(D) CRLF CRLF . {
14175 + http_req *req = ctx->req;
14178 + req->protocol = D;
14179 + buffer_copy_string_buffer(req->uri_raw, C);
14184 +method(A) ::= STRING(B) . {
14185 + A = get_http_method_key(BUF_STR(B));
14190 +protocol(A) ::= STRING(B). {
14191 + /* the protocol might be HTTP/1.0 or HTTP/1.1
14192 + * the version string is allowed to have leading zeros
14194 + A = HTTP_VERSION_UNSET;
14196 + if (0 == strncmp(BUF_STR(B), "HTTP/", 5)) {
14197 + char *err = NULL;
14198 + /* is there a dot */
14199 + char *major, *minor;
14201 + major = BUF_STR(B) + 5;
14202 + minor = strchr(major, '.');
14205 + hi = strtol(major, &err, 10);
14207 + if (*err == '.' && *minor != '\0') {
14208 + lo = strtol(minor, &err, 10);
14209 + if (*err == '\0') {
14210 + if (hi == 1 && lo == 1) {
14211 + A = HTTP_VERSION_1_1;
14212 + } else if (hi == 1 && lo == 0) {
14213 + A = HTTP_VERSION_1_0;
14223 +headers(HDRS) ::= headers(SRC) header(HDR). {
14227 + array_insert_unique(HDRS, (data_unset *)HDR);
14231 +headers(HDRS) ::= header(HDR). {
14233 + HDRS = array_init();
14235 + array_insert_unique(HDRS, (data_unset *)HDR);
14239 +header(HDR) ::= STRING(A) COLON multiline(B). {
14240 + HDR = data_string_init();
14242 + buffer_copy_string_buffer(HDR->key, A);
14243 + buffer_copy_string_buffer(HDR->value, B);
14248 +header(HDR) ::= STRING COLON CRLF . {
14249 + /* ignore empty header fields */
14254 +multiline(A) ::= STRING(B) CRLF TAB multiline(C). {
14255 + buffer_append_string_buffer(B, C);
14262 +/* the simple form */
14263 +multiline(A) ::= STRING(B) CRLF. {
14270 --- ../lighttpd-1.4.11/src/http_req_range.c 1970-01-01 03:00:00.000000000 +0300
14271 +++ lighttpd-1.5.0/src/http_req_range.c 2006-09-07 00:57:05.000000000 +0300
14273 +#include <string.h>
14274 +#include <stdlib.h>
14275 +#include <stdio.h>
14276 +#include <assert.h>
14279 +#include "http_req_range.h"
14280 +#include "http_req_range_parser.h"
14282 +/* declare prototypes for the parser */
14283 +void *http_req_range_parserAlloc(void *(*mallocProc)(size_t));
14284 +void http_req_range_parserFree(void *p, void (*freeProc)(void*));
14285 +void http_req_range_parserTrace(FILE *TraceFILE, char *zTracePrompt);
14286 +void http_req_range_parser(void *, int, buffer *, http_req_range_ctx_t *);
14293 + size_t lookup_offset;
14294 +} http_req_range_tokenizer_t;
14296 +http_req_range *http_request_range_init(void) {
14297 + http_req_range *range = calloc(1, sizeof(*range));
14299 + range->start = -1;
14305 +void http_request_range_reset(http_req_range *range) {
14306 + if (!range) return;
14308 + http_request_range_free(range->next);
14310 + range->next = NULL;
14312 + range->start = -1;
14316 +void http_request_range_free(http_req_range *range) {
14317 + if (!range) return;
14319 + http_request_range_free(range->next);
14324 +static int http_req_range_tokenizer(
14325 + http_req_range_tokenizer_t *t,
14331 + /* push the token to the parser */
14333 + while (tid == 0) {
14334 + char c = t->hdr->ptr[t->ndx];
14361 + /* 'bytes' or a number */
14362 + if (0 == strncmp(t->hdr->ptr + t->ndx, "bytes", 5)) {
14369 + for (d = t->ndx; d < t->hdr->used; d++) {
14370 + char dc = t->hdr->ptr[d];
14371 + if (dc < '0' || dc > '9') {
14376 + if (d == t->ndx) {
14377 + /* no digit found */
14379 + TRACE("%s", "no digit found");
14386 + buffer_copy_string_len(token, t->hdr->ptr + t->ndx, d - t->ndx);
14404 +parse_status_t http_request_range_parse(buffer *hdr, http_req_range *ranges) {
14405 + http_req_range_tokenizer_t t;
14406 + void *pParser = NULL;
14407 + int token_id = 0;
14408 + buffer *token = NULL;
14409 + http_req_range_ctx_t context;
14410 + parse_status_t ret = PARSE_UNSET;
14416 + context.errmsg = buffer_init();
14417 + context.ranges = ranges;
14419 + pParser = http_req_range_parserAlloc( malloc );
14420 + token = buffer_init();
14422 + http_req_range_parserTrace(stderr, "range: ");
14425 + while((1 == http_req_range_tokenizer(&t, &token_id, token)) && context.ok) {
14426 + http_req_range_parser(pParser, token_id, token, &context);
14428 + token = buffer_init();
14431 + /* oops, the parser failed */
14432 + if (context.ok == 0) {
14433 + ret = PARSE_ERROR;
14435 + if (!buffer_is_empty(context.errmsg)) {
14436 + TRACE("parsing failed: %s", BUF_STR(context.errmsg));
14438 + TRACE("%s", "parsing failed ...");
14442 + http_req_range_parser(pParser, 0, token, &context);
14443 + http_req_range_parserFree(pParser, free);
14445 + if (context.ok == 0) {
14446 + /* we are missing the some tokens */
14448 + if (!buffer_is_empty(context.errmsg)) {
14449 + TRACE("parsing failed: %s", BUF_STR(context.errmsg));
14452 + if (ret == PARSE_UNSET) {
14453 + ret = buffer_is_empty(context.errmsg) ? PARSE_NEED_MORE : PARSE_ERROR;
14456 + ret = PARSE_SUCCESS;
14459 + buffer_free(token);
14460 + buffer_free(context.errmsg);
14465 --- ../lighttpd-1.4.11/src/http_req_range.h 1970-01-01 03:00:00.000000000 +0300
14466 +++ lighttpd-1.5.0/src/http_req_range.h 2006-09-07 00:57:05.000000000 +0300
14468 +#ifndef _HTTP_REQ_RANGE_H_
14469 +#define _HTTP_REQ_RANGE_H_
14471 +#include "array.h"
14472 +#include "chunk.h"
14473 +#include "http_parser.h"
14475 +typedef struct _http_req_range {
14478 + struct _http_req_range *next;
14485 + http_req_range *ranges;
14486 +} http_req_range_ctx_t;
14488 +http_req_range *http_request_range_init(void);
14489 +void http_request_range_free(http_req_range *range);
14490 +void http_request_range_reset(http_req_range *range);
14492 +parse_status_t http_request_range_parse(buffer *range_hdr, http_req_range *ranges);
14495 --- ../lighttpd-1.4.11/src/http_req_range_parser.c 1970-01-01 03:00:00.000000000 +0300
14496 +++ lighttpd-1.5.0/src/http_req_range_parser.c 2006-09-07 01:00:42.000000000 +0300
14498 +/* Driver template for the LEMON parser generator.
14499 +** The author disclaims copyright to this source code.
14501 +/* First off, code is include which follows the "include" declaration
14502 +** in the input file. */
14503 +#include <stdio.h>
14504 +#line 6 "./http_req_range_parser.y"
14506 +#ifdef HAVE_CONFIG_H
14507 +#include "config.h"
14509 +#include <sys/types.h>
14510 +#include <string.h>
14511 +#include "http_req_range.h"
14514 +#line 18 "http_req_range_parser.c"
14515 +/* Next is all token values, in a form suitable for use by makeheaders.
14516 +** This section will be null unless lemon is run with the -m switch.
14519 +** These constants (all generated automatically by the parser generator)
14520 +** specify the various kinds of tokens (terminals) that the parser
14523 +** Each symbol here is a terminal symbol in the grammar.
14525 +/* Make sure the INTERFACE macro is defined.
14528 +# define INTERFACE 1
14530 +/* The next thing included is series of defines which control
14531 +** various aspects of the generated parser.
14532 +** YYCODETYPE is the data type used for storing terminal
14533 +** and nonterminal numbers. "unsigned char" is
14534 +** used if there are fewer than 250 terminals
14535 +** and nonterminals. "int" is used otherwise.
14536 +** YYNOCODE is a number of type YYCODETYPE which corresponds
14537 +** to no legal terminal or nonterminal number. This
14538 +** number is used to fill in empty slots of the hash
14540 +** YYFALLBACK If defined, this indicates that one or more tokens
14541 +** have fall-back values which should be used if the
14542 +** original value of the token will not parse.
14543 +** YYACTIONTYPE is the data type used for storing terminal
14544 +** and nonterminal numbers. "unsigned char" is
14545 +** used if there are fewer than 250 rules and
14546 +** states combined. "int" is used otherwise.
14547 +** http_req_range_parserTOKENTYPE is the data type used for minor tokens given
14548 +** directly to the parser from the tokenizer.
14549 +** YYMINORTYPE is the data type used for all minor tokens.
14550 +** This is typically a union of many types, one of
14551 +** which is http_req_range_parserTOKENTYPE. The entry in the union
14552 +** for base tokens is called "yy0".
14553 +** YYSTACKDEPTH is the maximum depth of the parser's stack.
14554 +** http_req_range_parserARG_SDECL A static variable declaration for the %extra_argument
14555 +** http_req_range_parserARG_PDECL A parameter declaration for the %extra_argument
14556 +** http_req_range_parserARG_STORE Code to store %extra_argument into yypParser
14557 +** http_req_range_parserARG_FETCH Code to extract %extra_argument from yypParser
14558 +** YYNSTATE the combined number of states.
14559 +** YYNRULE the number of rules in the grammar
14560 +** YYERRORSYMBOL is the code number of the error symbol. If not
14561 +** defined, then do no error processing.
14564 +#define YYCODETYPE unsigned char
14565 +#define YYNOCODE 12
14566 +#define YYACTIONTYPE unsigned char
14567 +#define http_req_range_parserTOKENTYPE buffer *
14569 + http_req_range_parserTOKENTYPE yy0;
14570 + http_req_range * yy18;
14574 +#define YYSTACKDEPTH 100
14575 +#define http_req_range_parserARG_SDECL http_req_range_ctx_t *ctx;
14576 +#define http_req_range_parserARG_PDECL ,http_req_range_ctx_t *ctx
14577 +#define http_req_range_parserARG_FETCH http_req_range_ctx_t *ctx = yypParser->ctx
14578 +#define http_req_range_parserARG_STORE yypParser->ctx = ctx
14579 +#define YYNSTATE 13
14581 +#define YYERRORSYMBOL 6
14582 +#define YYERRSYMDT yy23
14583 +#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
14584 +#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
14585 +#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
14587 +/* Next are that tables used to determine what action to take based on the
14588 +** current state and lookahead token. These tables are used to implement
14589 +** functions that take a state number and lookahead value and return an
14590 +** action integer.
14592 +** Suppose the action integer is N. Then the action is determined as
14595 +** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
14596 +** token onto the stack and goto state N.
14598 +** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
14600 +** N == YYNSTATE+YYNRULE A syntax error has occurred.
14602 +** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
14604 +** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
14605 +** slots in the yy_action[] table.
14607 +** The action table is constructed as a single large table named yy_action[].
14608 +** Given state S and lookahead X, the action is computed as
14610 +** yy_action[ yy_shift_ofst[S] + X ]
14612 +** If the index value yy_shift_ofst[S]+X is out of range or if the value
14613 +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
14614 +** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
14615 +** and that yy_default[S] should be used instead.
14617 +** The formula above is for computing the action when the lookahead is
14618 +** a terminal symbol. If the lookahead is a non-terminal (as occurs after
14619 +** a reduce action) then the yy_reduce_ofst[] array is used in place of
14620 +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
14621 +** YY_SHIFT_USE_DFLT.
14623 +** The following are the tables generated in this section:
14625 +** yy_action[] A single table containing all actions.
14626 +** yy_lookahead[] A table containing the lookahead for each entry in
14627 +** yy_action. Used to detect hash collisions.
14628 +** yy_shift_ofst[] For each state, the offset into yy_action for
14629 +** shifting terminals.
14630 +** yy_reduce_ofst[] For each state, the offset into yy_action for
14631 +** shifting non-terminals after a reduce.
14632 +** yy_default[] Default action for each state.
14634 +static YYACTIONTYPE yy_action[] = {
14635 + /* 0 */ 6, 12, 3, 10, 9, 13, 21, 1, 4, 6,
14636 + /* 10 */ 5, 2, 7, 20, 8, 9, 20, 20, 11,
14638 +static YYCODETYPE yy_lookahead[] = {
14639 + /* 0 */ 7, 8, 9, 4, 5, 0, 10, 1, 3, 7,
14640 + /* 10 */ 8, 2, 4, 11, 7, 5, 11, 11, 7,
14642 +#define YY_SHIFT_USE_DFLT (-2)
14643 +static signed char yy_shift_ofst[] = {
14644 + /* 0 */ 6, 9, -1, 5, -1, -2, 8, 10, -2, -2,
14645 + /* 10 */ 10, -2, -2,
14647 +#define YY_REDUCE_USE_DFLT (-8)
14648 +static signed char yy_reduce_ofst[] = {
14649 + /* 0 */ -4, -8, -7, -8, 2, -8, -8, 7, -8, -8,
14650 + /* 10 */ 11, -8, -8,
14652 +static YYACTIONTYPE yy_default[] = {
14653 + /* 0 */ 20, 20, 20, 20, 20, 14, 20, 16, 17, 19,
14654 + /* 10 */ 20, 18, 15,
14656 +#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
14658 +/* The next table maps tokens into fallback tokens. If a construct
14659 +** like the following:
14661 +** %fallback ID X Y Z.
14663 +** appears in the grammer, then ID becomes a fallback token for X, Y,
14664 +** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
14665 +** but it does not parse, the type of the token is changed to ID and
14666 +** the parse is retried before an error is thrown.
14669 +static const YYCODETYPE yyFallback[] = {
14671 +#endif /* YYFALLBACK */
14673 +/* The following structure represents a single element of the
14674 +** parser's stack. Information stored includes:
14676 +** + The state number for the parser at this level of the stack.
14678 +** + The value of the token stored at this level of the stack.
14679 +** (In other words, the "major" token.)
14681 +** + The semantic value stored at this level of the stack. This is
14682 +** the information used by the action routines in the grammar.
14683 +** It is sometimes called the "minor" token.
14685 +struct yyStackEntry {
14686 + int stateno; /* The state-number */
14687 + int major; /* The major token value. This is the code
14688 + ** number for the token at this stack level */
14689 + YYMINORTYPE minor; /* The user-supplied minor token value. This
14690 + ** is the value of the token */
14692 +typedef struct yyStackEntry yyStackEntry;
14694 +/* The state of the parser is completely contained in an instance of
14695 +** the following structure */
14697 + int yyidx; /* Index of top element in stack */
14698 + int yyerrcnt; /* Shifts left before out of the error */
14699 + http_req_range_parserARG_SDECL /* A place to hold %extra_argument */
14700 + yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
14702 +typedef struct yyParser yyParser;
14705 +#include <stdio.h>
14706 +static FILE *yyTraceFILE = 0;
14707 +static char *yyTracePrompt = 0;
14708 +#endif /* NDEBUG */
14712 +** Turn parser tracing on by giving a stream to which to write the trace
14713 +** and a prompt to preface each trace message. Tracing is turned off
14714 +** by making either argument NULL
14718 +** <li> A FILE* to which trace output should be written.
14719 +** If NULL, then tracing is turned off.
14720 +** <li> A prefix string written at the beginning of every
14721 +** line of trace output. If NULL, then tracing is
14728 +void http_req_range_parserTrace(FILE *TraceFILE, char *zTracePrompt){
14729 + yyTraceFILE = TraceFILE;
14730 + yyTracePrompt = zTracePrompt;
14731 + if( yyTraceFILE==0 ) yyTracePrompt = 0;
14732 + else if( yyTracePrompt==0 ) yyTraceFILE = 0;
14734 +#endif /* NDEBUG */
14737 +/* For tracing shifts, the names of all terminals and nonterminals
14738 +** are required. The following table supplies these names */
14739 +static const char *yyTokenName[] = {
14740 + "$", "BYTES", "EQUAL", "COMMA",
14741 + "MINUS", "NUMBER", "error", "num",
14742 + "range", "ranges", "range_hdr",
14744 +#endif /* NDEBUG */
14747 +/* For tracing reduce actions, the names of all rules are required.
14749 +static const char *yyRuleName[] = {
14750 + /* 0 */ "range_hdr ::= BYTES EQUAL ranges",
14751 + /* 1 */ "ranges ::= ranges COMMA range",
14752 + /* 2 */ "ranges ::= range",
14753 + /* 3 */ "range ::= num MINUS",
14754 + /* 4 */ "range ::= num MINUS num",
14755 + /* 5 */ "range ::= MINUS num",
14756 + /* 6 */ "num ::= NUMBER",
14758 +#endif /* NDEBUG */
14761 +** This function returns the symbolic name associated with a token
14764 +const char *http_req_range_parserTokenName(int tokenType){
14766 + if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
14767 + return yyTokenName[tokenType];
14769 + return "Unknown";
14777 +** This function allocates a new parser.
14778 +** The only argument is a pointer to a function which works like
14782 +** A pointer to the function used to allocate memory.
14785 +** A pointer to a parser. This pointer is used in subsequent calls
14786 +** to http_req_range_parser and http_req_range_parserFree.
14788 +void *http_req_range_parserAlloc(void *(*mallocProc)(size_t)){
14789 + yyParser *pParser;
14790 + pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
14792 + pParser->yyidx = -1;
14797 +/* The following function deletes the value associated with a
14798 +** symbol. The symbol can be either a terminal or nonterminal.
14799 +** "yymajor" is the symbol code, and "yypminor" is a pointer to
14802 +static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
14803 + switch( yymajor ){
14804 + /* Here is inserted the actions which take place when a
14805 + ** terminal or non-terminal is destroyed. This can happen
14806 + ** when the symbol is popped from the stack during a
14807 + ** reduce or during error processing or when a parser is
14808 + ** being destroyed before it is finished parsing.
14810 + ** Note: during a reduce, the only symbols destroyed are those
14811 + ** which appear on the RHS of the rule, but which are not used
14812 + ** inside the C code.
14819 +#line 23 "./http_req_range_parser.y"
14820 +{ buffer_free((yypminor->yy0)); }
14821 +#line 324 "http_req_range_parser.c"
14823 + default: break; /* If no destructor action specified: do nothing */
14828 +** Pop the parser's stack once.
14830 +** If there is a destructor routine associated with the token which
14831 +** is popped from the stack, then call it.
14833 +** Return the major token number for the symbol popped.
14835 +static int yy_pop_parser_stack(yyParser *pParser){
14836 + YYCODETYPE yymajor;
14837 + yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
14839 + if( pParser->yyidx<0 ) return 0;
14841 + if( yyTraceFILE && pParser->yyidx>=0 ){
14842 + fprintf(yyTraceFILE,"%sPopping %s\n",
14844 + yyTokenName[yytos->major]);
14847 + yymajor = yytos->major;
14848 + yy_destructor( yymajor, &yytos->minor);
14849 + pParser->yyidx--;
14854 +** Deallocate and destroy a parser. Destructors are all called for
14855 +** all stack elements before shutting the parser down.
14859 +** <li> A pointer to the parser. This should be a pointer
14860 +** obtained from http_req_range_parserAlloc.
14861 +** <li> A pointer to a function used to reclaim memory obtained
14865 +void http_req_range_parserFree(
14866 + void *p, /* The parser to be deleted */
14867 + void (*freeProc)(void*) /* Function used to reclaim memory */
14869 + yyParser *pParser = (yyParser*)p;
14870 + if( pParser==0 ) return;
14871 + while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
14872 + (*freeProc)((void*)pParser);
14876 +** Find the appropriate action for a parser given the terminal
14877 +** look-ahead token iLookAhead.
14879 +** If the look-ahead token is YYNOCODE, then check to see if the action is
14880 +** independent of the look-ahead. If it is, return the action, otherwise
14881 +** return YY_NO_ACTION.
14883 +static int yy_find_shift_action(
14884 + yyParser *pParser, /* The parser */
14885 + int iLookAhead /* The look-ahead token */
14888 + int stateno = pParser->yystack[pParser->yyidx].stateno;
14890 + /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
14891 + i = yy_shift_ofst[stateno];
14892 + if( i==YY_SHIFT_USE_DFLT ){
14893 + return yy_default[stateno];
14895 + if( iLookAhead==YYNOCODE ){
14896 + return YY_NO_ACTION;
14899 + if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
14901 + int iFallback; /* Fallback token */
14902 + if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
14903 + && (iFallback = yyFallback[iLookAhead])!=0 ){
14905 + if( yyTraceFILE ){
14906 + fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
14907 + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
14910 + return yy_find_shift_action(pParser, iFallback);
14913 + return yy_default[stateno];
14915 + return yy_action[i];
14920 +** Find the appropriate action for a parser given the non-terminal
14921 +** look-ahead token iLookAhead.
14923 +** If the look-ahead token is YYNOCODE, then check to see if the action is
14924 +** independent of the look-ahead. If it is, return the action, otherwise
14925 +** return YY_NO_ACTION.
14927 +static int yy_find_reduce_action(
14928 + yyParser *pParser, /* The parser */
14929 + int iLookAhead /* The look-ahead token */
14932 + int stateno = pParser->yystack[pParser->yyidx].stateno;
14934 + i = yy_reduce_ofst[stateno];
14935 + if( i==YY_REDUCE_USE_DFLT ){
14936 + return yy_default[stateno];
14938 + if( iLookAhead==YYNOCODE ){
14939 + return YY_NO_ACTION;
14942 + if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
14943 + return yy_default[stateno];
14945 + return yy_action[i];
14950 +** Perform a shift action.
14952 +static void yy_shift(
14953 + yyParser *yypParser, /* The parser to be shifted */
14954 + int yyNewState, /* The new state to shift in */
14955 + int yyMajor, /* The major token to shift in */
14956 + YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */
14958 + yyStackEntry *yytos;
14959 + yypParser->yyidx++;
14960 + if( yypParser->yyidx>=YYSTACKDEPTH ){
14961 + http_req_range_parserARG_FETCH;
14962 + yypParser->yyidx--;
14964 + if( yyTraceFILE ){
14965 + fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
14968 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
14969 + /* Here code is inserted which will execute if the parser
14970 + ** stack every overflows */
14971 + http_req_range_parserARG_STORE; /* Suppress warning about unused %extra_argument var */
14974 + yytos = &yypParser->yystack[yypParser->yyidx];
14975 + yytos->stateno = yyNewState;
14976 + yytos->major = yyMajor;
14977 + yytos->minor = *yypMinor;
14979 + if( yyTraceFILE && yypParser->yyidx>0 ){
14981 + fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
14982 + fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
14983 + for(i=1; i<=yypParser->yyidx; i++)
14984 + fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
14985 + fprintf(yyTraceFILE,"\n");
14990 +/* The following table contains information about every rule that
14991 +** is used during the reduce.
14994 + YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
14995 + unsigned char nrhs; /* Number of right-hand side symbols in the rule */
14996 +} yyRuleInfo[] = {
15006 +static void yy_accept(yyParser*); /* Forward Declaration */
15009 +** Perform a reduce action and the shift that must immediately
15010 +** follow the reduce.
15012 +static void yy_reduce(
15013 + yyParser *yypParser, /* The parser */
15014 + int yyruleno /* Number of the rule by which to reduce */
15016 + int yygoto; /* The next state */
15017 + int yyact; /* The next action */
15018 + YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
15019 + yyStackEntry *yymsp; /* The top of the parser's stack */
15020 + int yysize; /* Amount to pop the stack */
15021 + http_req_range_parserARG_FETCH;
15022 + yymsp = &yypParser->yystack[yypParser->yyidx];
15024 + if( yyTraceFILE && yyruleno>=0
15025 + && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
15026 + fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
15027 + yyRuleName[yyruleno]);
15029 +#endif /* NDEBUG */
15031 + switch( yyruleno ){
15032 + /* Beginning here are the reduction cases. A typical example
15035 + ** #line <lineno> <grammarfile>
15036 + ** { ... } // User supplied code
15037 + ** #line <lineno> <thisfile>
15041 +#line 26 "./http_req_range_parser.y"
15043 + ctx->ranges->start = yymsp[0].minor.yy18->start;
15044 + ctx->ranges->end = yymsp[0].minor.yy18->end;
15045 + ctx->ranges->next = yymsp[0].minor.yy18->next;
15047 + yymsp[0].minor.yy18->next = NULL;
15048 + http_request_range_free(yymsp[0].minor.yy18);
15050 +#line 553 "http_req_range_parser.c"
15051 + yy_destructor(1,&yymsp[-2].minor);
15052 + yy_destructor(2,&yymsp[-1].minor);
15055 +#line 35 "./http_req_range_parser.y"
15057 + for (yygotominor.yy18 = yymsp[-2].minor.yy18; yygotominor.yy18->next; yygotominor.yy18 = yygotominor.yy18->next);
15059 + yygotominor.yy18->next = yymsp[0].minor.yy18;
15061 + yygotominor.yy18 = yymsp[-2].minor.yy18;
15063 +#line 566 "http_req_range_parser.c"
15064 + yy_destructor(3,&yymsp[-1].minor);
15067 +#line 42 "./http_req_range_parser.y"
15069 + yygotominor.yy18 = yymsp[0].minor.yy18;
15071 +#line 574 "http_req_range_parser.c"
15074 +#line 45 "./http_req_range_parser.y"
15076 + http_req_range *r = http_request_range_init();
15078 + r->start = yymsp[-1].minor.yy19;
15081 + yygotominor.yy18 = r;
15083 +#line 586 "http_req_range_parser.c"
15084 + yy_destructor(4,&yymsp[0].minor);
15087 +#line 54 "./http_req_range_parser.y"
15089 + http_req_range *r = http_request_range_init();
15091 + r->start = yymsp[-2].minor.yy19;
15092 + r->end = yymsp[0].minor.yy19;
15094 + yygotominor.yy18 = r;
15096 +#line 599 "http_req_range_parser.c"
15097 + yy_destructor(4,&yymsp[-1].minor);
15100 +#line 63 "./http_req_range_parser.y"
15102 + http_req_range *r = http_request_range_init();
15105 + r->end = yymsp[0].minor.yy19;
15107 + yygotominor.yy18 = r;
15109 +#line 612 "http_req_range_parser.c"
15110 + yy_destructor(4,&yymsp[-1].minor);
15113 +#line 72 "./http_req_range_parser.y"
15115 + yygotominor.yy19 = strtoull(BUF_STR(yymsp[0].minor.yy0), NULL, 10);
15117 +#line 620 "http_req_range_parser.c"
15120 + yygoto = yyRuleInfo[yyruleno].lhs;
15121 + yysize = yyRuleInfo[yyruleno].nrhs;
15122 + yypParser->yyidx -= yysize;
15123 + yyact = yy_find_reduce_action(yypParser,yygoto);
15124 + if( yyact < YYNSTATE ){
15125 + yy_shift(yypParser,yyact,yygoto,&yygotominor);
15126 + }else if( yyact == YYNSTATE + YYNRULE + 1 ){
15127 + yy_accept(yypParser);
15132 +** The following code executes when the parse fails
15134 +static void yy_parse_failed(
15135 + yyParser *yypParser /* The parser */
15137 + http_req_range_parserARG_FETCH;
15139 + if( yyTraceFILE ){
15140 + fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
15143 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
15144 + /* Here code is inserted which will be executed whenever the
15145 + ** parser fails */
15146 +#line 16 "./http_req_range_parser.y"
15150 +#line 653 "http_req_range_parser.c"
15151 + http_req_range_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
15155 +** The following code executes when a syntax error first occurs.
15157 +static void yy_syntax_error(
15158 + yyParser *yypParser, /* The parser */
15159 + int yymajor, /* The major type of the error token */
15160 + YYMINORTYPE yyminor /* The minor type of the error token */
15162 + http_req_range_parserARG_FETCH;
15163 +#define TOKEN (yyminor.yy0)
15164 + http_req_range_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
15168 +** The following is executed when the parser accepts
15170 +static void yy_accept(
15171 + yyParser *yypParser /* The parser */
15173 + http_req_range_parserARG_FETCH;
15175 + if( yyTraceFILE ){
15176 + fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
15179 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
15180 + /* Here code is inserted which will be executed whenever the
15181 + ** parser accepts */
15182 + http_req_range_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
15185 +/* The main parser program.
15186 +** The first argument is a pointer to a structure obtained from
15187 +** "http_req_range_parserAlloc" which describes the current state of the parser.
15188 +** The second argument is the major token number. The third is
15189 +** the minor token. The fourth optional argument is whatever the
15190 +** user wants (and specified in the grammar) and is available for
15191 +** use by the action routines.
15195 +** <li> A pointer to the parser (an opaque structure.)
15196 +** <li> The major token number.
15197 +** <li> The minor token number.
15198 +** <li> An option argument of a grammar-specified type.
15204 +void http_req_range_parser(
15205 + void *yyp, /* The parser */
15206 + int yymajor, /* The major token code number */
15207 + http_req_range_parserTOKENTYPE yyminor /* The value for the token */
15208 + http_req_range_parserARG_PDECL /* Optional %extra_argument parameter */
15210 + YYMINORTYPE yyminorunion;
15211 + int yyact; /* The parser action. */
15212 + int yyendofinput; /* True if we are at the end of input */
15213 + int yyerrorhit = 0; /* True if yymajor has invoked an error */
15214 + yyParser *yypParser; /* The parser */
15216 + /* (re)initialize the parser, if necessary */
15217 + yypParser = (yyParser*)yyp;
15218 + if( yypParser->yyidx<0 ){
15219 + if( yymajor==0 ) return;
15220 + yypParser->yyidx = 0;
15221 + yypParser->yyerrcnt = -1;
15222 + yypParser->yystack[0].stateno = 0;
15223 + yypParser->yystack[0].major = 0;
15225 + yyminorunion.yy0 = yyminor;
15226 + yyendofinput = (yymajor==0);
15227 + http_req_range_parserARG_STORE;
15230 + if( yyTraceFILE ){
15231 + fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
15236 + yyact = yy_find_shift_action(yypParser,yymajor);
15237 + if( yyact<YYNSTATE ){
15238 + yy_shift(yypParser,yyact,yymajor,&yyminorunion);
15239 + yypParser->yyerrcnt--;
15240 + if( yyendofinput && yypParser->yyidx>=0 ){
15243 + yymajor = YYNOCODE;
15245 + }else if( yyact < YYNSTATE + YYNRULE ){
15246 + yy_reduce(yypParser,yyact-YYNSTATE);
15247 + }else if( yyact == YY_ERROR_ACTION ){
15250 + if( yyTraceFILE ){
15251 + fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
15254 +#ifdef YYERRORSYMBOL
15255 + /* A syntax error has occurred.
15256 + ** The response to an error depends upon whether or not the
15257 + ** grammar defines an error token "ERROR".
15259 + ** This is what we do if the grammar does define ERROR:
15261 + ** * Call the %syntax_error function.
15263 + ** * Begin popping the stack until we enter a state where
15264 + ** it is legal to shift the error symbol, then shift
15265 + ** the error symbol.
15267 + ** * Set the error count to three.
15269 + ** * Begin accepting and shifting new tokens. No new error
15270 + ** processing will occur until three tokens have been
15271 + ** shifted successfully.
15274 + if( yypParser->yyerrcnt<0 ){
15275 + yy_syntax_error(yypParser,yymajor,yyminorunion);
15277 + yymx = yypParser->yystack[yypParser->yyidx].major;
15278 + if( yymx==YYERRORSYMBOL || yyerrorhit ){
15280 + if( yyTraceFILE ){
15281 + fprintf(yyTraceFILE,"%sDiscard input token %s\n",
15282 + yyTracePrompt,yyTokenName[yymajor]);
15285 + yy_destructor(yymajor,&yyminorunion);
15286 + yymajor = YYNOCODE;
15289 + yypParser->yyidx >= 0 &&
15290 + yymx != YYERRORSYMBOL &&
15291 + (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
15293 + yy_pop_parser_stack(yypParser);
15295 + if( yypParser->yyidx < 0 || yymajor==0 ){
15296 + yy_destructor(yymajor,&yyminorunion);
15297 + yy_parse_failed(yypParser);
15298 + yymajor = YYNOCODE;
15299 + }else if( yymx!=YYERRORSYMBOL ){
15301 + u2.YYERRSYMDT = 0;
15302 + yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
15305 + yypParser->yyerrcnt = 3;
15307 +#else /* YYERRORSYMBOL is not defined */
15308 + /* This is what we do if the grammar does not define ERROR:
15310 + ** * Report an error message, and throw away the input token.
15312 + ** * If the input token is $, then fail the parse.
15314 + ** As before, subsequent error messages are suppressed until
15315 + ** three input tokens have been successfully shifted.
15317 + if( yypParser->yyerrcnt<=0 ){
15318 + yy_syntax_error(yypParser,yymajor,yyminorunion);
15320 + yypParser->yyerrcnt = 3;
15321 + yy_destructor(yymajor,&yyminorunion);
15322 + if( yyendofinput ){
15323 + yy_parse_failed(yypParser);
15325 + yymajor = YYNOCODE;
15328 + yy_accept(yypParser);
15329 + yymajor = YYNOCODE;
15331 + }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
15334 --- ../lighttpd-1.4.11/src/http_req_range_parser.h 1970-01-01 03:00:00.000000000 +0300
15335 +++ lighttpd-1.5.0/src/http_req_range_parser.h 2006-09-07 01:00:42.000000000 +0300
15337 +#define TK_BYTES 1
15338 +#define TK_EQUAL 2
15339 +#define TK_COMMA 3
15340 +#define TK_MINUS 4
15341 +#define TK_NUMBER 5
15342 --- ../lighttpd-1.4.11/src/http_req_range_parser.y 1970-01-01 03:00:00.000000000 +0300
15343 +++ lighttpd-1.5.0/src/http_req_range_parser.y 2006-09-07 00:57:05.000000000 +0300
15346 +%token_type {buffer *}
15347 +%extra_argument {http_req_range_ctx_t *ctx}
15348 +%name http_req_range_parser
15351 +#ifdef HAVE_CONFIG_H
15352 +#include "config.h"
15354 +#include <sys/types.h>
15355 +#include <string.h>
15356 +#include "http_req_range.h"
15364 +%type num { off_t }
15365 +%type range { http_req_range * }
15366 +%type ranges { http_req_range * }
15367 +%token_destructor { buffer_free($$); }
15370 +range_hdr ::= BYTES EQUAL ranges(A) . {
15371 + ctx->ranges->start = A->start;
15372 + ctx->ranges->end = A->end;
15373 + ctx->ranges->next = A->next;
15376 + http_request_range_free(A);
15379 +ranges(A) ::= ranges(B) COMMA range(C) . {
15380 + for (A = B; A->next; A = A->next);
15386 +ranges(A) ::= range(B) . {
15389 +range(A) ::= num(B) MINUS . {
15390 + http_req_range *r = http_request_range_init();
15398 +range(A) ::= num(B) MINUS num(C) . {
15399 + http_req_range *r = http_request_range_init();
15407 +range(A) ::= MINUS num(B) . {
15408 + http_req_range *r = http_request_range_init();
15416 +num(A) ::= NUMBER(B) . {
15417 + A = strtoull(BUF_STR(B), NULL, 10);
15419 --- ../lighttpd-1.4.11/src/http_resp.c 1970-01-01 03:00:00.000000000 +0300
15420 +++ lighttpd-1.5.0/src/http_resp.c 2006-07-18 13:03:40.000000000 +0300
15422 +#include <string.h>
15423 +#include <stdlib.h>
15424 +#include <stdio.h>
15425 +#include <assert.h>
15428 +#include "http_resp.h"
15429 +#include "http_resp_parser.h"
15431 +/* declare prototypes for the parser */
15432 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t));
15433 +void http_resp_parserFree(void *p, void (*freeProc)(void*));
15434 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt);
15435 +void http_resp_parser(void *, int, buffer *, http_resp_ctx_t *);
15440 + chunk *c; /* current chunk in the chunkqueue */
15441 + size_t offset; /* current offset in current chunk */
15444 + size_t lookup_offset;
15447 + int is_statusline;
15448 +} http_resp_tokenizer_t;
15450 +http_resp *http_response_init(void) {
15451 + http_resp *resp = calloc(1, sizeof(*resp));
15453 + resp->reason = buffer_init();
15454 + resp->headers = array_init();
15459 +void http_response_reset(http_resp *resp) {
15460 + if (!resp) return;
15462 + buffer_reset(resp->reason);
15463 + array_reset(resp->headers);
15467 +void http_response_free(http_resp *resp) {
15468 + if (!resp) return;
15470 + buffer_free(resp->reason);
15471 + array_free(resp->headers);
15476 +static int http_resp_get_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
15477 + if (t->offset == t->c->mem->used - 1) {
15478 + /* end of chunk, open next chunk */
15480 + if (!t->c->next) return -1;
15482 + t->c = t->c->next;
15486 + *c = t->c->mem->ptr[t->offset++];
15488 + t->lookup_offset = t->offset;
15489 + t->lookup_c = t->c;
15492 + fprintf(stderr, "%s.%d: get: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->offset - 1);
15498 +static int http_resp_lookup_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
15499 + if (t->lookup_offset == t->lookup_c->mem->used - 1) {
15500 + /* end of chunk, open next chunk */
15502 + if (!t->lookup_c->next) return -1;
15504 + t->lookup_c = t->lookup_c->next;
15505 + t->lookup_offset = 0;
15508 + *c = t->lookup_c->mem->ptr[t->lookup_offset++];
15510 + fprintf(stderr, "%s.%d: lookup: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->lookup_offset - 1);
15517 +static int http_resp_tokenizer(
15518 + http_resp_tokenizer_t *t,
15525 + /* push the token to the parser */
15527 + while (tid == 0 && 0 == http_resp_get_next_char(t, &c)) {
15541 + if (0 != http_resp_lookup_next_char(t, &c)) return -1;
15546 + t->c = t->lookup_c;
15547 + t->offset = t->lookup_offset;
15549 + t->is_statusline = 0;
15552 + fprintf(stderr, "%s.%d: CR with out LF\r\n", __FILE__, __LINE__);
15559 + t->is_statusline = 0;
15564 + while (c >= 32 && c != 127 && c != 255) {
15565 + if (t->is_statusline) {
15566 + if (c == ':') { t->is_statusline = 0; break; } /* this is not a status line by a real header */
15567 + if (c == 32) break; /* the space is a splitter in the statusline */
15570 + if (c == ':') break; /* the : is the splitter between key and value */
15573 + if (0 != http_resp_lookup_next_char(t, &c)) return -1;
15576 + if (t->c == t->lookup_c &&
15577 + t->offset == t->lookup_offset + 1) {
15579 + fprintf(stderr, "%s.%d: invalid char in string\n", __FILE__, __LINE__);
15585 + /* the lookup points to the first invalid char */
15586 + t->lookup_offset--;
15588 + /* no overlapping string */
15589 + if (t->c == t->lookup_c) {
15590 + buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->lookup_offset - t->offset + 1);
15592 + /* first chunk */
15593 + buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->c->mem->used - t->offset);
15595 + /* chunks in the middle */
15596 + for (t->c = t->c->next; t->c != t->lookup_c; t->c = t->c->next) {
15597 + buffer_append_string_buffer(token, t->c->mem);
15598 + t->offset = t->c->mem->used - 1;
15602 + buffer_append_string_len(token, t->c->mem->ptr, t->lookup_offset);
15605 + t->offset = t->lookup_offset;
15620 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *resp) {
15621 + http_resp_tokenizer_t t;
15622 + void *pParser = NULL;
15623 + int token_id = 0;
15624 + buffer *token = NULL;
15625 + http_resp_ctx_t context;
15626 + parse_status_t ret = PARSE_UNSET;
15627 + int last_token_id = 0;
15631 + t.offset = t.c->offset;
15633 + t.is_statusline = 1;
15636 + context.errmsg = buffer_init();
15637 + context.resp = resp;
15639 + pParser = http_resp_parserAlloc( malloc );
15640 + token = buffer_init();
15642 + http_resp_parserTrace(stderr, "http-response: ");
15645 + while((1 == http_resp_tokenizer(&t, &token_id, token)) && context.ok) {
15646 + http_resp_parser(pParser, token_id, token, &context);
15648 + token = buffer_init();
15650 + /* CRLF CRLF ... the header end sequence */
15651 + if (last_token_id == TK_CRLF &&
15652 + token_id == TK_CRLF) break;
15654 + last_token_id = token_id;
15657 + /* oops, the parser failed */
15658 + if (context.ok == 0) {
15659 + ret = PARSE_ERROR;
15661 + if (!buffer_is_empty(context.errmsg)) {
15662 + TRACE("parsing failed: %s", BUF_STR(context.errmsg));
15664 + TRACE("%s", "parsing failed ...");
15668 + http_resp_parser(pParser, 0, token, &context);
15669 + http_resp_parserFree(pParser, free);
15671 + if (context.ok == 0) {
15672 + /* we are missing the some tokens */
15674 + if (!buffer_is_empty(context.errmsg)) {
15675 + TRACE("parsing failed: %s", BUF_STR(context.errmsg));
15678 + if (ret == PARSE_UNSET) {
15679 + ret = buffer_is_empty(context.errmsg) ? PARSE_NEED_MORE : PARSE_ERROR;
15684 + for (c = cq->first; c != t.c; c = c->next) {
15685 + c->offset = c->mem->used - 1;
15688 + c->offset = t.offset;
15690 + ret = PARSE_SUCCESS;
15693 + buffer_free(token);
15694 + buffer_free(context.errmsg);
15699 --- ../lighttpd-1.4.11/src/http_resp.h 1970-01-01 03:00:00.000000000 +0300
15700 +++ lighttpd-1.5.0/src/http_resp.h 2006-09-07 00:57:05.000000000 +0300
15702 +#ifndef _HTTP_RESP_H_
15703 +#define _HTTP_RESP_H_
15705 +#include "array.h"
15706 +#include "chunk.h"
15707 +#include "http_parser.h"
15710 + int protocol; /* http/1.0, http/1.1 */
15711 + int status; /* e.g. 200 */
15712 + buffer *reason; /* e.g. Ok */
15721 +} http_resp_ctx_t;
15723 +http_resp *http_response_init(void);
15724 +void http_response_free(http_resp *resp);
15725 +void http_response_reset(http_resp *resp);
15727 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *http_response);
15730 --- ../lighttpd-1.4.11/src/http_resp_parser.c 1970-01-01 03:00:00.000000000 +0300
15731 +++ lighttpd-1.5.0/src/http_resp_parser.c 2006-09-07 00:57:07.000000000 +0300
15733 +/* Driver template for the LEMON parser generator.
15734 +** The author disclaims copyright to this source code.
15736 +/* First off, code is include which follows the "include" declaration
15737 +** in the input file. */
15738 +#include <stdio.h>
15739 +#line 6 "./http_resp_parser.y"
15741 +#include <assert.h>
15742 +#include <string.h>
15743 +#include "http_resp.h"
15744 +#include "keyvalue.h"
15745 +#include "array.h"
15748 +#line 17 "http_resp_parser.c"
15749 +/* Next is all token values, in a form suitable for use by makeheaders.
15750 +** This section will be null unless lemon is run with the -m switch.
15753 +** These constants (all generated automatically by the parser generator)
15754 +** specify the various kinds of tokens (terminals) that the parser
15757 +** Each symbol here is a terminal symbol in the grammar.
15759 +/* Make sure the INTERFACE macro is defined.
15762 +# define INTERFACE 1
15764 +/* The next thing included is series of defines which control
15765 +** various aspects of the generated parser.
15766 +** YYCODETYPE is the data type used for storing terminal
15767 +** and nonterminal numbers. "unsigned char" is
15768 +** used if there are fewer than 250 terminals
15769 +** and nonterminals. "int" is used otherwise.
15770 +** YYNOCODE is a number of type YYCODETYPE which corresponds
15771 +** to no legal terminal or nonterminal number. This
15772 +** number is used to fill in empty slots of the hash
15774 +** YYFALLBACK If defined, this indicates that one or more tokens
15775 +** have fall-back values which should be used if the
15776 +** original value of the token will not parse.
15777 +** YYACTIONTYPE is the data type used for storing terminal
15778 +** and nonterminal numbers. "unsigned char" is
15779 +** used if there are fewer than 250 rules and
15780 +** states combined. "int" is used otherwise.
15781 +** http_resp_parserTOKENTYPE is the data type used for minor tokens given
15782 +** directly to the parser from the tokenizer.
15783 +** YYMINORTYPE is the data type used for all minor tokens.
15784 +** This is typically a union of many types, one of
15785 +** which is http_resp_parserTOKENTYPE. The entry in the union
15786 +** for base tokens is called "yy0".
15787 +** YYSTACKDEPTH is the maximum depth of the parser's stack.
15788 +** http_resp_parserARG_SDECL A static variable declaration for the %extra_argument
15789 +** http_resp_parserARG_PDECL A parameter declaration for the %extra_argument
15790 +** http_resp_parserARG_STORE Code to store %extra_argument into yypParser
15791 +** http_resp_parserARG_FETCH Code to extract %extra_argument from yypParser
15792 +** YYNSTATE the combined number of states.
15793 +** YYNRULE the number of rules in the grammar
15794 +** YYERRORSYMBOL is the code number of the error symbol. If not
15795 +** defined, then do no error processing.
15798 +#define YYCODETYPE unsigned char
15799 +#define YYNOCODE 12
15800 +#define YYACTIONTYPE unsigned char
15801 +#define http_resp_parserTOKENTYPE buffer *
15803 + http_resp_parserTOKENTYPE yy0;
15805 + data_string * yy9;
15810 +#define YYSTACKDEPTH 100
15811 +#define http_resp_parserARG_SDECL http_resp_ctx_t *ctx;
15812 +#define http_resp_parserARG_PDECL ,http_resp_ctx_t *ctx
15813 +#define http_resp_parserARG_FETCH http_resp_ctx_t *ctx = yypParser->ctx
15814 +#define http_resp_parserARG_STORE yypParser->ctx = ctx
15815 +#define YYNSTATE 19
15817 +#define YYERRORSYMBOL 4
15818 +#define YYERRSYMDT yy23
15819 +#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
15820 +#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
15821 +#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
15823 +/* Next are that tables used to determine what action to take based on the
15824 +** current state and lookahead token. These tables are used to implement
15825 +** functions that take a state number and lookahead value and return an
15826 +** action integer.
15828 +** Suppose the action integer is N. Then the action is determined as
15831 +** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
15832 +** token onto the stack and goto state N.
15834 +** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
15836 +** N == YYNSTATE+YYNRULE A syntax error has occurred.
15838 +** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
15840 +** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
15841 +** slots in the yy_action[] table.
15843 +** The action table is constructed as a single large table named yy_action[].
15844 +** Given state S and lookahead X, the action is computed as
15846 +** yy_action[ yy_shift_ofst[S] + X ]
15848 +** If the index value yy_shift_ofst[S]+X is out of range or if the value
15849 +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
15850 +** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
15851 +** and that yy_default[S] should be used instead.
15853 +** The formula above is for computing the action when the lookahead is
15854 +** a terminal symbol. If the lookahead is a non-terminal (as occurs after
15855 +** a reduce action) then the yy_reduce_ofst[] array is used in place of
15856 +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
15857 +** YY_SHIFT_USE_DFLT.
15859 +** The following are the tables generated in this section:
15861 +** yy_action[] A single table containing all actions.
15862 +** yy_lookahead[] A table containing the lookahead for each entry in
15863 +** yy_action. Used to detect hash collisions.
15864 +** yy_shift_ofst[] For each state, the offset into yy_action for
15865 +** shifting terminals.
15866 +** yy_reduce_ofst[] For each state, the offset into yy_action for
15867 +** shifting non-terminals after a reduce.
15868 +** yy_default[] Default action for each state.
15870 +static YYACTIONTYPE yy_action[] = {
15871 + /* 0 */ 8, 29, 18, 1, 14, 2, 4, 11, 15, 12,
15872 + /* 10 */ 14, 13, 4, 21, 5, 19, 3, 5, 6, 7,
15873 + /* 20 */ 9, 17, 16, 4, 20, 22, 22, 10,
15875 +static YYCODETYPE yy_lookahead[] = {
15876 + /* 0 */ 5, 6, 2, 8, 9, 1, 2, 1, 2, 8,
15877 + /* 10 */ 9, 1, 2, 2, 3, 0, 9, 3, 2, 1,
15878 + /* 20 */ 7, 2, 2, 2, 0, 2, 11, 10,
15880 +#define YY_SHIFT_USE_DFLT (-1)
15881 +static signed char yy_shift_ofst[] = {
15882 + /* 0 */ 0, 4, 15, -1, 14, 16, 18, -1, 19, 20,
15883 + /* 10 */ 6, 21, 10, 24, -1, -1, -1, 23, 11,
15885 +#define YY_REDUCE_USE_DFLT (-6)
15886 +static signed char yy_reduce_ofst[] = {
15887 + /* 0 */ -5, 7, -6, -6, -6, -6, -6, -6, 13, 17,
15888 + /* 10 */ -6, 1, 7, -6, -6, -6, -6, -6, -6,
15890 +static YYACTIONTYPE yy_default[] = {
15891 + /* 0 */ 28, 28, 28, 25, 28, 28, 28, 27, 28, 28,
15892 + /* 10 */ 28, 28, 28, 28, 26, 24, 23, 28, 28,
15894 +#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
15896 +/* The next table maps tokens into fallback tokens. If a construct
15897 +** like the following:
15899 +** %fallback ID X Y Z.
15901 +** appears in the grammer, then ID becomes a fallback token for X, Y,
15902 +** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
15903 +** but it does not parse, the type of the token is changed to ID and
15904 +** the parse is retried before an error is thrown.
15907 +static const YYCODETYPE yyFallback[] = {
15909 +#endif /* YYFALLBACK */
15911 +/* The following structure represents a single element of the
15912 +** parser's stack. Information stored includes:
15914 +** + The state number for the parser at this level of the stack.
15916 +** + The value of the token stored at this level of the stack.
15917 +** (In other words, the "major" token.)
15919 +** + The semantic value stored at this level of the stack. This is
15920 +** the information used by the action routines in the grammar.
15921 +** It is sometimes called the "minor" token.
15923 +struct yyStackEntry {
15924 + int stateno; /* The state-number */
15925 + int major; /* The major token value. This is the code
15926 + ** number for the token at this stack level */
15927 + YYMINORTYPE minor; /* The user-supplied minor token value. This
15928 + ** is the value of the token */
15930 +typedef struct yyStackEntry yyStackEntry;
15932 +/* The state of the parser is completely contained in an instance of
15933 +** the following structure */
15935 + int yyidx; /* Index of top element in stack */
15936 + int yyerrcnt; /* Shifts left before out of the error */
15937 + http_resp_parserARG_SDECL /* A place to hold %extra_argument */
15938 + yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
15940 +typedef struct yyParser yyParser;
15943 +#include <stdio.h>
15944 +static FILE *yyTraceFILE = 0;
15945 +static char *yyTracePrompt = 0;
15946 +#endif /* NDEBUG */
15950 +** Turn parser tracing on by giving a stream to which to write the trace
15951 +** and a prompt to preface each trace message. Tracing is turned off
15952 +** by making either argument NULL
15956 +** <li> A FILE* to which trace output should be written.
15957 +** If NULL, then tracing is turned off.
15958 +** <li> A prefix string written at the beginning of every
15959 +** line of trace output. If NULL, then tracing is
15966 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt){
15967 + yyTraceFILE = TraceFILE;
15968 + yyTracePrompt = zTracePrompt;
15969 + if( yyTraceFILE==0 ) yyTracePrompt = 0;
15970 + else if( yyTracePrompt==0 ) yyTraceFILE = 0;
15972 +#endif /* NDEBUG */
15975 +/* For tracing shifts, the names of all terminals and nonterminals
15976 +** are required. The following table supplies these names */
15977 +static const char *yyTokenName[] = {
15978 + "$", "CRLF", "STRING", "COLON",
15979 + "error", "protocol", "response_hdr", "number",
15980 + "headers", "header", "reason",
15982 +#endif /* NDEBUG */
15985 +/* For tracing reduce actions, the names of all rules are required.
15987 +static const char *yyRuleName[] = {
15988 + /* 0 */ "response_hdr ::= headers CRLF",
15989 + /* 1 */ "response_hdr ::= protocol number reason CRLF headers CRLF",
15990 + /* 2 */ "protocol ::= STRING",
15991 + /* 3 */ "number ::= STRING",
15992 + /* 4 */ "reason ::= STRING",
15993 + /* 5 */ "reason ::= reason STRING",
15994 + /* 6 */ "headers ::= headers header",
15995 + /* 7 */ "headers ::= header",
15996 + /* 8 */ "header ::= STRING COLON STRING CRLF",
15998 +#endif /* NDEBUG */
16001 +** This function returns the symbolic name associated with a token
16004 +const char *http_resp_parserTokenName(int tokenType){
16006 + if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
16007 + return yyTokenName[tokenType];
16009 + return "Unknown";
16017 +** This function allocates a new parser.
16018 +** The only argument is a pointer to a function which works like
16022 +** A pointer to the function used to allocate memory.
16025 +** A pointer to a parser. This pointer is used in subsequent calls
16026 +** to http_resp_parser and http_resp_parserFree.
16028 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t)){
16029 + yyParser *pParser;
16030 + pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
16032 + pParser->yyidx = -1;
16037 +/* The following function deletes the value associated with a
16038 +** symbol. The symbol can be either a terminal or nonterminal.
16039 +** "yymajor" is the symbol code, and "yypminor" is a pointer to
16042 +static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
16043 + switch( yymajor ){
16044 + /* Here is inserted the actions which take place when a
16045 + ** terminal or non-terminal is destroyed. This can happen
16046 + ** when the symbol is popped from the stack during a
16047 + ** reduce or during error processing or when a parser is
16048 + ** being destroyed before it is finished parsing.
16050 + ** Note: during a reduce, the only symbols destroyed are those
16051 + ** which appear on the RHS of the rule, but which are not used
16052 + ** inside the C code.
16057 +#line 25 "./http_resp_parser.y"
16058 +{ buffer_free((yypminor->yy0)); }
16059 +#line 327 "http_resp_parser.c"
16062 +#line 24 "./http_resp_parser.y"
16063 +{ buffer_free((yypminor->yy0)); }
16064 +#line 332 "http_resp_parser.c"
16066 + default: break; /* If no destructor action specified: do nothing */
16071 +** Pop the parser's stack once.
16073 +** If there is a destructor routine associated with the token which
16074 +** is popped from the stack, then call it.
16076 +** Return the major token number for the symbol popped.
16078 +static int yy_pop_parser_stack(yyParser *pParser){
16079 + YYCODETYPE yymajor;
16080 + yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
16082 + if( pParser->yyidx<0 ) return 0;
16084 + if( yyTraceFILE && pParser->yyidx>=0 ){
16085 + fprintf(yyTraceFILE,"%sPopping %s\n",
16087 + yyTokenName[yytos->major]);
16090 + yymajor = yytos->major;
16091 + yy_destructor( yymajor, &yytos->minor);
16092 + pParser->yyidx--;
16097 +** Deallocate and destroy a parser. Destructors are all called for
16098 +** all stack elements before shutting the parser down.
16102 +** <li> A pointer to the parser. This should be a pointer
16103 +** obtained from http_resp_parserAlloc.
16104 +** <li> A pointer to a function used to reclaim memory obtained
16108 +void http_resp_parserFree(
16109 + void *p, /* The parser to be deleted */
16110 + void (*freeProc)(void*) /* Function used to reclaim memory */
16112 + yyParser *pParser = (yyParser*)p;
16113 + if( pParser==0 ) return;
16114 + while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
16115 + (*freeProc)((void*)pParser);
16119 +** Find the appropriate action for a parser given the terminal
16120 +** look-ahead token iLookAhead.
16122 +** If the look-ahead token is YYNOCODE, then check to see if the action is
16123 +** independent of the look-ahead. If it is, return the action, otherwise
16124 +** return YY_NO_ACTION.
16126 +static int yy_find_shift_action(
16127 + yyParser *pParser, /* The parser */
16128 + int iLookAhead /* The look-ahead token */
16131 + int stateno = pParser->yystack[pParser->yyidx].stateno;
16133 + /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
16134 + i = yy_shift_ofst[stateno];
16135 + if( i==YY_SHIFT_USE_DFLT ){
16136 + return yy_default[stateno];
16138 + if( iLookAhead==YYNOCODE ){
16139 + return YY_NO_ACTION;
16142 + if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
16144 + int iFallback; /* Fallback token */
16145 + if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
16146 + && (iFallback = yyFallback[iLookAhead])!=0 ){
16148 + if( yyTraceFILE ){
16149 + fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
16150 + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
16153 + return yy_find_shift_action(pParser, iFallback);
16156 + return yy_default[stateno];
16158 + return yy_action[i];
16163 +** Find the appropriate action for a parser given the non-terminal
16164 +** look-ahead token iLookAhead.
16166 +** If the look-ahead token is YYNOCODE, then check to see if the action is
16167 +** independent of the look-ahead. If it is, return the action, otherwise
16168 +** return YY_NO_ACTION.
16170 +static int yy_find_reduce_action(
16171 + yyParser *pParser, /* The parser */
16172 + int iLookAhead /* The look-ahead token */
16175 + int stateno = pParser->yystack[pParser->yyidx].stateno;
16177 + i = yy_reduce_ofst[stateno];
16178 + if( i==YY_REDUCE_USE_DFLT ){
16179 + return yy_default[stateno];
16181 + if( iLookAhead==YYNOCODE ){
16182 + return YY_NO_ACTION;
16185 + if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
16186 + return yy_default[stateno];
16188 + return yy_action[i];
16193 +** Perform a shift action.
16195 +static void yy_shift(
16196 + yyParser *yypParser, /* The parser to be shifted */
16197 + int yyNewState, /* The new state to shift in */
16198 + int yyMajor, /* The major token to shift in */
16199 + YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */
16201 + yyStackEntry *yytos;
16202 + yypParser->yyidx++;
16203 + if( yypParser->yyidx>=YYSTACKDEPTH ){
16204 + http_resp_parserARG_FETCH;
16205 + yypParser->yyidx--;
16207 + if( yyTraceFILE ){
16208 + fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
16211 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
16212 + /* Here code is inserted which will execute if the parser
16213 + ** stack every overflows */
16214 + http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument var */
16217 + yytos = &yypParser->yystack[yypParser->yyidx];
16218 + yytos->stateno = yyNewState;
16219 + yytos->major = yyMajor;
16220 + yytos->minor = *yypMinor;
16222 + if( yyTraceFILE && yypParser->yyidx>0 ){
16224 + fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
16225 + fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
16226 + for(i=1; i<=yypParser->yyidx; i++)
16227 + fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
16228 + fprintf(yyTraceFILE,"\n");
16233 +/* The following table contains information about every rule that
16234 +** is used during the reduce.
16237 + YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
16238 + unsigned char nrhs; /* Number of right-hand side symbols in the rule */
16239 +} yyRuleInfo[] = {
16251 +static void yy_accept(yyParser*); /* Forward Declaration */
16254 +** Perform a reduce action and the shift that must immediately
16255 +** follow the reduce.
16257 +static void yy_reduce(
16258 + yyParser *yypParser, /* The parser */
16259 + int yyruleno /* Number of the rule by which to reduce */
16261 + int yygoto; /* The next state */
16262 + int yyact; /* The next action */
16263 + YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
16264 + yyStackEntry *yymsp; /* The top of the parser's stack */
16265 + int yysize; /* Amount to pop the stack */
16266 + http_resp_parserARG_FETCH;
16267 + yymsp = &yypParser->yystack[yypParser->yyidx];
16269 + if( yyTraceFILE && yyruleno>=0
16270 + && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
16271 + fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
16272 + yyRuleName[yyruleno]);
16274 +#endif /* NDEBUG */
16276 + switch( yyruleno ){
16277 + /* Beginning here are the reduction cases. A typical example
16280 + ** #line <lineno> <grammarfile>
16281 + ** { ... } // User supplied code
16282 + ** #line <lineno> <thisfile>
16286 +#line 28 "./http_resp_parser.y"
16288 + http_resp *resp = ctx->resp;
16291 + resp->protocol = HTTP_VERSION_UNSET;
16293 + buffer_copy_string(resp->reason, ""); /* no reason */
16294 + array_free(resp->headers);
16295 + resp->headers = yymsp[-1].minor.yy12;
16297 + if (NULL == (ds = (data_string *)array_get_element(yymsp[-1].minor.yy12, "Status"))) {
16298 + resp->status = 0;
16301 + resp->status = strtol(ds->value->ptr, &err, 10);
16303 + if (*err != '\0' && *err != ' ') {
16304 + buffer_copy_string(ctx->errmsg, "expected a number: ");
16305 + buffer_append_string_buffer(ctx->errmsg, ds->value);
16306 + buffer_append_string(ctx->errmsg, err);
16312 + yymsp[-1].minor.yy12 = NULL;
16314 +#line 582 "http_resp_parser.c"
16315 + yy_destructor(1,&yymsp[0].minor);
16318 +#line 56 "./http_resp_parser.y"
16320 + http_resp *resp = ctx->resp;
16322 + resp->status = yymsp[-4].minor.yy20;
16323 + resp->protocol = yymsp[-5].minor.yy20;
16324 + buffer_copy_string_buffer(resp->reason, yymsp[-3].minor.yy0);
16325 + buffer_free(yymsp[-3].minor.yy0);
16327 + array_free(resp->headers);
16329 + resp->headers = yymsp[-1].minor.yy12;
16331 +#line 599 "http_resp_parser.c"
16332 + yy_destructor(1,&yymsp[-2].minor);
16333 + yy_destructor(1,&yymsp[0].minor);
16336 +#line 69 "./http_resp_parser.y"
16338 + if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.0"))) {
16339 + yygotominor.yy20 = HTTP_VERSION_1_0;
16340 + } else if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.1"))) {
16341 + yygotominor.yy20 = HTTP_VERSION_1_1;
16343 + buffer_copy_string(ctx->errmsg, "unknown protocol: ");
16344 + buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
16348 + buffer_free(yymsp[0].minor.yy0);
16350 +#line 618 "http_resp_parser.c"
16353 +#line 83 "./http_resp_parser.y"
16356 + yygotominor.yy20 = strtol(yymsp[0].minor.yy0->ptr, &err, 10);
16358 + if (*err != '\0') {
16359 + buffer_copy_string(ctx->errmsg, "expected a number, got: ");
16360 + buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
16364 + buffer_free(yymsp[0].minor.yy0);
16366 +#line 634 "http_resp_parser.c"
16369 +#line 96 "./http_resp_parser.y"
16371 + yygotominor.yy0 = yymsp[0].minor.yy0;
16373 +#line 641 "http_resp_parser.c"
16376 +#line 100 "./http_resp_parser.y"
16378 + yygotominor.yy0 = yymsp[-1].minor.yy0;
16380 + buffer_append_string(yygotominor.yy0, " ");
16381 + buffer_append_string_buffer(yygotominor.yy0, yymsp[0].minor.yy0);
16383 + buffer_free(yymsp[0].minor.yy0);
16385 +#line 653 "http_resp_parser.c"
16388 +#line 109 "./http_resp_parser.y"
16390 + yygotominor.yy12 = yymsp[-1].minor.yy12;
16392 + array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
16394 +#line 662 "http_resp_parser.c"
16397 +#line 115 "./http_resp_parser.y"
16399 + yygotominor.yy12 = array_init();
16401 + array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
16403 +#line 671 "http_resp_parser.c"
16406 +#line 120 "./http_resp_parser.y"
16408 + yygotominor.yy9 = data_response_init();
16410 + buffer_copy_string_buffer(yygotominor.yy9->key, yymsp[-3].minor.yy0);
16411 + buffer_copy_string_buffer(yygotominor.yy9->value, yymsp[-1].minor.yy0);
16412 + buffer_free(yymsp[-3].minor.yy0);
16413 + buffer_free(yymsp[-1].minor.yy0);
16415 +#line 683 "http_resp_parser.c"
16416 + yy_destructor(3,&yymsp[-2].minor);
16417 + yy_destructor(1,&yymsp[0].minor);
16420 + yygoto = yyRuleInfo[yyruleno].lhs;
16421 + yysize = yyRuleInfo[yyruleno].nrhs;
16422 + yypParser->yyidx -= yysize;
16423 + yyact = yy_find_reduce_action(yypParser,yygoto);
16424 + if( yyact < YYNSTATE ){
16425 + yy_shift(yypParser,yyact,yygoto,&yygotominor);
16426 + }else if( yyact == YYNSTATE + YYNRULE + 1 ){
16427 + yy_accept(yypParser);
16432 +** The following code executes when the parse fails
16434 +static void yy_parse_failed(
16435 + yyParser *yypParser /* The parser */
16437 + http_resp_parserARG_FETCH;
16439 + if( yyTraceFILE ){
16440 + fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
16443 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
16444 + /* Here code is inserted which will be executed whenever the
16445 + ** parser fails */
16446 +#line 15 "./http_resp_parser.y"
16450 +#line 718 "http_resp_parser.c"
16451 + http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
16455 +** The following code executes when a syntax error first occurs.
16457 +static void yy_syntax_error(
16458 + yyParser *yypParser, /* The parser */
16459 + int yymajor, /* The major type of the error token */
16460 + YYMINORTYPE yyminor /* The minor type of the error token */
16462 + http_resp_parserARG_FETCH;
16463 +#define TOKEN (yyminor.yy0)
16464 + http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
16468 +** The following is executed when the parser accepts
16470 +static void yy_accept(
16471 + yyParser *yypParser /* The parser */
16473 + http_resp_parserARG_FETCH;
16475 + if( yyTraceFILE ){
16476 + fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
16479 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
16480 + /* Here code is inserted which will be executed whenever the
16481 + ** parser accepts */
16482 + http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
16485 +/* The main parser program.
16486 +** The first argument is a pointer to a structure obtained from
16487 +** "http_resp_parserAlloc" which describes the current state of the parser.
16488 +** The second argument is the major token number. The third is
16489 +** the minor token. The fourth optional argument is whatever the
16490 +** user wants (and specified in the grammar) and is available for
16491 +** use by the action routines.
16495 +** <li> A pointer to the parser (an opaque structure.)
16496 +** <li> The major token number.
16497 +** <li> The minor token number.
16498 +** <li> An option argument of a grammar-specified type.
16504 +void http_resp_parser(
16505 + void *yyp, /* The parser */
16506 + int yymajor, /* The major token code number */
16507 + http_resp_parserTOKENTYPE yyminor /* The value for the token */
16508 + http_resp_parserARG_PDECL /* Optional %extra_argument parameter */
16510 + YYMINORTYPE yyminorunion;
16511 + int yyact; /* The parser action. */
16512 + int yyendofinput; /* True if we are at the end of input */
16513 + int yyerrorhit = 0; /* True if yymajor has invoked an error */
16514 + yyParser *yypParser; /* The parser */
16516 + /* (re)initialize the parser, if necessary */
16517 + yypParser = (yyParser*)yyp;
16518 + if( yypParser->yyidx<0 ){
16519 + if( yymajor==0 ) return;
16520 + yypParser->yyidx = 0;
16521 + yypParser->yyerrcnt = -1;
16522 + yypParser->yystack[0].stateno = 0;
16523 + yypParser->yystack[0].major = 0;
16525 + yyminorunion.yy0 = yyminor;
16526 + yyendofinput = (yymajor==0);
16527 + http_resp_parserARG_STORE;
16530 + if( yyTraceFILE ){
16531 + fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
16536 + yyact = yy_find_shift_action(yypParser,yymajor);
16537 + if( yyact<YYNSTATE ){
16538 + yy_shift(yypParser,yyact,yymajor,&yyminorunion);
16539 + yypParser->yyerrcnt--;
16540 + if( yyendofinput && yypParser->yyidx>=0 ){
16543 + yymajor = YYNOCODE;
16545 + }else if( yyact < YYNSTATE + YYNRULE ){
16546 + yy_reduce(yypParser,yyact-YYNSTATE);
16547 + }else if( yyact == YY_ERROR_ACTION ){
16550 + if( yyTraceFILE ){
16551 + fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
16554 +#ifdef YYERRORSYMBOL
16555 + /* A syntax error has occurred.
16556 + ** The response to an error depends upon whether or not the
16557 + ** grammar defines an error token "ERROR".
16559 + ** This is what we do if the grammar does define ERROR:
16561 + ** * Call the %syntax_error function.
16563 + ** * Begin popping the stack until we enter a state where
16564 + ** it is legal to shift the error symbol, then shift
16565 + ** the error symbol.
16567 + ** * Set the error count to three.
16569 + ** * Begin accepting and shifting new tokens. No new error
16570 + ** processing will occur until three tokens have been
16571 + ** shifted successfully.
16574 + if( yypParser->yyerrcnt<0 ){
16575 + yy_syntax_error(yypParser,yymajor,yyminorunion);
16577 + yymx = yypParser->yystack[yypParser->yyidx].major;
16578 + if( yymx==YYERRORSYMBOL || yyerrorhit ){
16580 + if( yyTraceFILE ){
16581 + fprintf(yyTraceFILE,"%sDiscard input token %s\n",
16582 + yyTracePrompt,yyTokenName[yymajor]);
16585 + yy_destructor(yymajor,&yyminorunion);
16586 + yymajor = YYNOCODE;
16589 + yypParser->yyidx >= 0 &&
16590 + yymx != YYERRORSYMBOL &&
16591 + (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
16593 + yy_pop_parser_stack(yypParser);
16595 + if( yypParser->yyidx < 0 || yymajor==0 ){
16596 + yy_destructor(yymajor,&yyminorunion);
16597 + yy_parse_failed(yypParser);
16598 + yymajor = YYNOCODE;
16599 + }else if( yymx!=YYERRORSYMBOL ){
16601 + u2.YYERRSYMDT = 0;
16602 + yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
16605 + yypParser->yyerrcnt = 3;
16607 +#else /* YYERRORSYMBOL is not defined */
16608 + /* This is what we do if the grammar does not define ERROR:
16610 + ** * Report an error message, and throw away the input token.
16612 + ** * If the input token is $, then fail the parse.
16614 + ** As before, subsequent error messages are suppressed until
16615 + ** three input tokens have been successfully shifted.
16617 + if( yypParser->yyerrcnt<=0 ){
16618 + yy_syntax_error(yypParser,yymajor,yyminorunion);
16620 + yypParser->yyerrcnt = 3;
16621 + yy_destructor(yymajor,&yyminorunion);
16622 + if( yyendofinput ){
16623 + yy_parse_failed(yypParser);
16625 + yymajor = YYNOCODE;
16628 + yy_accept(yypParser);
16629 + yymajor = YYNOCODE;
16631 + }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
16634 --- ../lighttpd-1.4.11/src/http_resp_parser.h 1970-01-01 03:00:00.000000000 +0300
16635 +++ lighttpd-1.5.0/src/http_resp_parser.h 2006-09-07 00:57:07.000000000 +0300
16638 +#define TK_STRING 2
16639 +#define TK_COLON 3
16640 --- ../lighttpd-1.4.11/src/http_resp_parser.y 1970-01-01 03:00:00.000000000 +0300
16641 +++ lighttpd-1.5.0/src/http_resp_parser.y 2006-09-07 00:57:05.000000000 +0300
16644 +%token_type {buffer *}
16645 +%extra_argument {http_resp_ctx_t *ctx}
16646 +%name http_resp_parser
16649 +#include <assert.h>
16650 +#include <string.h>
16651 +#include "http_resp.h"
16652 +#include "keyvalue.h"
16653 +#include "array.h"
16661 +%type protocol { int }
16662 +%type response_hdr { http_resp * }
16663 +%type number { int }
16664 +%type headers { array * }
16665 +%type header { data_string * }
16666 +%destructor reason { buffer_free($$); }
16667 +%token_destructor { buffer_free($$); }
16669 +/* just headers + Status: ... */
16670 +response_hdr ::= headers(HDR) CRLF . {
16671 + http_resp *resp = ctx->resp;
16674 + resp->protocol = HTTP_VERSION_UNSET;
16676 + buffer_copy_string(resp->reason, ""); /* no reason */
16677 + array_free(resp->headers);
16678 + resp->headers = HDR;
16680 + if (NULL == (ds = (data_string *)array_get_element(HDR, "Status"))) {
16681 + resp->status = 0;
16684 + resp->status = strtol(ds->value->ptr, &err, 10);
16686 + if (*err != '\0' && *err != ' ') {
16687 + buffer_copy_string(ctx->errmsg, "expected a number: ");
16688 + buffer_append_string_buffer(ctx->errmsg, ds->value);
16689 + buffer_append_string(ctx->errmsg, err);
16697 +/* HTTP/1.0 <status> ... */
16698 +response_hdr ::= protocol(B) number(C) reason(D) CRLF headers(HDR) CRLF . {
16699 + http_resp *resp = ctx->resp;
16701 + resp->status = C;
16702 + resp->protocol = B;
16703 + buffer_copy_string_buffer(resp->reason, D);
16706 + array_free(resp->headers);
16708 + resp->headers = HDR;
16711 +protocol(A) ::= STRING(B). {
16712 + if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.0"))) {
16713 + A = HTTP_VERSION_1_0;
16714 + } else if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.1"))) {
16715 + A = HTTP_VERSION_1_1;
16717 + buffer_copy_string(ctx->errmsg, "unknown protocol: ");
16718 + buffer_append_string_buffer(ctx->errmsg, B);
16725 +number(A) ::= STRING(B). {
16727 + A = strtol(B->ptr, &err, 10);
16729 + if (*err != '\0') {
16730 + buffer_copy_string(ctx->errmsg, "expected a number, got: ");
16731 + buffer_append_string_buffer(ctx->errmsg, B);
16738 +reason(A) ::= STRING(B). {
16742 +reason(A) ::= reason(C) STRING(B). {
16745 + buffer_append_string(A, " ");
16746 + buffer_append_string_buffer(A, B);
16751 +headers(HDRS) ::= headers(SRC) header(HDR). {
16754 + array_insert_unique(HDRS, (data_unset *)HDR);
16757 +headers(HDRS) ::= header(HDR). {
16758 + HDRS = array_init();
16760 + array_insert_unique(HDRS, (data_unset *)HDR);
16762 +header(HDR) ::= STRING(A) COLON STRING(B) CRLF. {
16763 + HDR = data_response_init();
16765 + buffer_copy_string_buffer(HDR->key, A);
16766 + buffer_copy_string_buffer(HDR->value, B);
16770 --- ../lighttpd-1.4.11/src/inet_ntop_cache.c 2005-08-11 01:26:38.000000000 +0300
16771 +++ lighttpd-1.5.0/src/inet_ntop_cache.c 2006-07-16 00:26:04.000000000 +0300
16773 #include "sys-socket.h"
16775 const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) {
16779 for (i = 0; i < INET_NTOP_CACHE_MAX; i++) {
16780 if (srv->inet_ntop_cache[i].ts != 0) {
16781 @@ -20,31 +20,31 @@
16782 srv->inet_ntop_cache[i].addr.ipv4.s_addr == addr->ipv4.sin_addr.s_addr) {
16783 /* IPv4 found in cache */
16792 if (i == INET_NTOP_CACHE_MAX) {
16793 /* not found in cache */
16797 - inet_ntop(addr->plain.sa_family,
16798 - addr->plain.sa_family == AF_INET6 ?
16799 + inet_ntop(addr->plain.sa_family,
16800 + addr->plain.sa_family == AF_INET6 ?
16801 (const void *) &(addr->ipv6.sin6_addr) :
16802 (const void *) &(addr->ipv4.sin_addr),
16803 srv->inet_ntop_cache[i].b2, INET6_ADDRSTRLEN);
16806 srv->inet_ntop_cache[i].ts = srv->cur_ts;
16807 srv->inet_ntop_cache[i].family = addr->plain.sa_family;
16810 if (srv->inet_ntop_cache[i].family == AF_INET) {
16811 srv->inet_ntop_cache[i].addr.ipv4.s_addr = addr->ipv4.sin_addr.s_addr;
16812 } else if (srv->inet_ntop_cache[i].family == AF_INET6) {
16813 memcpy(srv->inet_ntop_cache[i].addr.ipv6.s6_addr, addr->ipv6.sin6_addr.s6_addr, 16);
16818 return srv->inet_ntop_cache[i].b2;
16821 --- ../lighttpd-1.4.11/src/iosocket.c 1970-01-01 03:00:00.000000000 +0300
16822 +++ lighttpd-1.5.0/src/iosocket.c 2006-07-18 13:03:40.000000000 +0300
16824 +#include <stdlib.h>
16826 +#include "iosocket.h"
16827 +#include "sys-socket.h"
16828 +#include "sys-files.h"
16829 +#include "array-static.h"
16831 +iosocket *iosocket_init(void) {
16832 + STRUCT_INIT(iosocket, sock);
16834 + sock->fde_ndx = -1;
16837 + sock->type = IOSOCKET_TYPE_SOCKET;
16842 +void iosocket_free(iosocket *sock) {
16843 + if (!sock) return;
16845 + if (sock->fd != -1) {
16846 + switch (sock->type) {
16847 + case IOSOCKET_TYPE_SOCKET:
16848 + closesocket(sock->fd);
16850 + case IOSOCKET_TYPE_PIPE:
16860 --- ../lighttpd-1.4.11/src/iosocket.h 1970-01-01 03:00:00.000000000 +0300
16861 +++ lighttpd-1.5.0/src/iosocket.h 2006-07-20 01:14:57.000000000 +0300
16863 +#ifndef _IOSOCKET_H_
16864 +#define _IOSOCKET_H_
16867 + * make sure we know about OPENSSL all the time
16869 + * if we don't include config.h here we run into different sizes
16870 + * for the iosocket-struct depending on config.h include before
16871 + * iosocket.h or not
16874 +#ifdef HAVE_CONFIG_H
16875 +# include "config.h"
16878 +#if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
16879 +# define USE_OPENSSL
16880 +# include <openssl/ssl.h>
16884 + IOSOCKET_TYPE_UNSET,
16885 + IOSOCKET_TYPE_SOCKET,
16886 + IOSOCKET_TYPE_PIPE
16890 + * a non-blocking fd
16896 +#ifdef USE_OPENSSL
16900 + iosocket_t type; /**< sendfile on solaris doesn't work on pipes */
16903 +iosocket *iosocket_init(void);
16904 +void iosocket_free(iosocket *sock);
16907 --- ../lighttpd-1.4.11/src/joblist.c 2005-08-11 01:26:41.000000000 +0300
16908 +++ lighttpd-1.5.0/src/joblist.c 2006-07-16 00:26:03.000000000 +0300
16911 int joblist_append(server *srv, connection *con) {
16912 if (con->in_joblist) return 0;
16915 if (srv->joblist->size == 0) {
16916 srv->joblist->size = 16;
16917 srv->joblist->ptr = malloc(sizeof(*srv->joblist->ptr) * srv->joblist->size);
16918 @@ -15,15 +15,15 @@
16919 srv->joblist->size += 16;
16920 srv->joblist->ptr = realloc(srv->joblist->ptr, sizeof(*srv->joblist->ptr) * srv->joblist->size);
16924 srv->joblist->ptr[srv->joblist->used++] = con;
16930 void joblist_free(server *srv, connections *joblist) {
16934 free(joblist->ptr);
16937 @@ -31,14 +31,14 @@
16938 connection *fdwaitqueue_unshift(server *srv, connections *fdwaitqueue) {
16945 if (fdwaitqueue->used == 0) return NULL;
16948 con = fdwaitqueue->ptr[0];
16951 memmove(fdwaitqueue->ptr, &(fdwaitqueue->ptr[1]), --fdwaitqueue->used * sizeof(*(fdwaitqueue->ptr)));
16958 srv->fdwaitqueue->size += 16;
16959 srv->fdwaitqueue->ptr = realloc(srv->fdwaitqueue->ptr, sizeof(*(srv->fdwaitqueue->ptr)) * srv->fdwaitqueue->size);
16963 srv->fdwaitqueue->ptr[srv->fdwaitqueue->used++] = con;
16969 --- ../lighttpd-1.4.11/src/keyvalue.c 2006-03-02 16:08:06.000000000 +0200
16970 +++ lighttpd-1.5.0/src/keyvalue.c 2006-07-16 00:26:03.000000000 +0300
16972 { 504, "Gateway Timeout" },
16973 { 505, "HTTP Version Not Supported" },
16974 { 507, "Insufficient Storage" }, /* WebDAV */
16976 + { 509, "Bandwidth Limit exceeded" },
16981 @@ -102,12 +103,12 @@
16982 { 501, "501.html" },
16983 { 503, "503.html" },
16984 { 505, "505.html" },
16991 -const char *keyvalue_get_value(keyvalue *kv, int k) {
16992 +const char *keyvalue_get_value(keyvalue *kv, int k) {
16994 for (i = 0; kv[i].value; i++) {
16995 if (kv[i].key == k) return kv[i].value;
16996 @@ -115,7 +116,7 @@
17000 -int keyvalue_get_key(keyvalue *kv, const char *s) {
17001 +int keyvalue_get_key(keyvalue *kv, const char *s) {
17003 for (i = 0; kv[i].value; i++) {
17004 if (0 == strcmp(kv[i].value, s)) return kv[i].key;
17005 @@ -125,9 +126,9 @@
17007 keyvalue_buffer *keyvalue_buffer_init(void) {
17008 keyvalue_buffer *kvb;
17011 kvb = calloc(1, sizeof(*kvb));
17017 @@ -135,49 +136,49 @@
17019 if (kvb->size == 0) {
17023 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
17026 for(i = 0; i < kvb->size; i++) {
17027 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
17029 } else if (kvb->used == kvb->size) {
17033 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
17036 for(i = kvb->used; i < kvb->size; i++) {
17037 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
17042 kvb->kv[kvb->used]->key = key;
17043 kvb->kv[kvb->used]->value = strdup(value);
17052 void keyvalue_buffer_free(keyvalue_buffer *kvb) {
17056 for (i = 0; i < kvb->size; i++) {
17057 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
17062 if (kvb->kv) free(kvb->kv);
17069 s_keyvalue_buffer *s_keyvalue_buffer_init(void) {
17070 s_keyvalue_buffer *kvb;
17073 kvb = calloc(1, sizeof(*kvb));
17079 @@ -186,50 +187,50 @@
17080 if (kvb->size == 0) {
17085 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
17088 for(i = 0; i < kvb->size; i++) {
17089 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
17091 } else if (kvb->used == kvb->size) {
17095 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
17098 for(i = kvb->used; i < kvb->size; i++) {
17099 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
17104 kvb->kv[kvb->used]->key = key ? strdup(key) : NULL;
17105 kvb->kv[kvb->used]->value = strdup(value);
17114 void s_keyvalue_buffer_free(s_keyvalue_buffer *kvb) {
17118 for (i = 0; i < kvb->size; i++) {
17119 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
17120 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
17125 if (kvb->kv) free(kvb->kv);
17132 httpauth_keyvalue_buffer *httpauth_keyvalue_buffer_init(void) {
17133 httpauth_keyvalue_buffer *kvb;
17136 kvb = calloc(1, sizeof(*kvb));
17142 @@ -237,42 +238,42 @@
17144 if (kvb->size == 0) {
17148 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
17151 for(i = 0; i < kvb->size; i++) {
17152 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
17154 } else if (kvb->used == kvb->size) {
17158 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
17161 for(i = kvb->used; i < kvb->size; i++) {
17162 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
17167 kvb->kv[kvb->used]->key = strdup(key);
17168 kvb->kv[kvb->used]->realm = strdup(realm);
17169 kvb->kv[kvb->used]->type = type;
17178 void httpauth_keyvalue_buffer_free(httpauth_keyvalue_buffer *kvb) {
17182 for (i = 0; i < kvb->size; i++) {
17183 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
17184 if (kvb->kv[i]->realm) free(kvb->kv[i]->realm);
17189 if (kvb->kv) free(kvb->kv);
17195 @@ -306,9 +307,9 @@
17197 pcre_keyvalue_buffer *pcre_keyvalue_buffer_init(void) {
17198 pcre_keyvalue_buffer *kvb;
17201 kvb = calloc(1, sizeof(*kvb));
17207 @@ -319,46 +320,46 @@
17213 if (!key) return -1;
17216 if (kvb->size == 0) {
17221 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
17224 for(i = 0; i < kvb->size; i++) {
17225 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
17227 } else if (kvb->used == kvb->size) {
17231 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
17234 for(i = kvb->used; i < kvb->size; i++) {
17235 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
17240 kv = kvb->kv[kvb->used];
17241 if (NULL == (kv->key = pcre_compile(key,
17242 0, &errptr, &erroff, NULL))) {
17245 fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr);
17249 - if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
17250 + if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
17256 kv->value = buffer_init_string(value);
17265 @@ -380,9 +381,9 @@
17266 if (kv->value) buffer_free(kv->value);
17271 if (kvb->kv) free(kvb->kv);
17277 --- ../lighttpd-1.4.11/src/keyvalue.h 2006-03-02 16:08:06.000000000 +0200
17278 +++ lighttpd-1.5.0/src/keyvalue.h 2006-09-07 00:57:05.000000000 +0300
17284 - HTTP_METHOD_UNSET = -1,
17286 - HTTP_METHOD_POST,
17287 - HTTP_METHOD_HEAD,
17288 - HTTP_METHOD_OPTIONS,
17290 + HTTP_METHOD_UNSET = -1,
17292 + HTTP_METHOD_POST,
17293 + HTTP_METHOD_HEAD,
17294 + HTTP_METHOD_OPTIONS,
17295 HTTP_METHOD_PROPFIND, /* WebDAV */
17296 - HTTP_METHOD_MKCOL,
17298 - HTTP_METHOD_DELETE,
17299 - HTTP_METHOD_COPY,
17300 - HTTP_METHOD_MOVE,
17301 - HTTP_METHOD_PROPPATCH,
17302 + HTTP_METHOD_MKCOL,
17304 + HTTP_METHOD_DELETE,
17305 + HTTP_METHOD_COPY,
17306 + HTTP_METHOD_MOVE,
17307 + HTTP_METHOD_PROPPATCH,
17308 HTTP_METHOD_REPORT, /* DeltaV */
17309 HTTP_METHOD_CHECKOUT,
17310 HTTP_METHOD_CHECKIN,
17311 @@ -35,17 +35,21 @@
17312 HTTP_METHOD_CONNECT
17315 -typedef enum { HTTP_VERSION_UNSET = -1, HTTP_VERSION_1_0, HTTP_VERSION_1_1 } http_version_t;
17317 + HTTP_VERSION_UNSET = -1,
17318 + HTTP_VERSION_1_0,
17338 pcre_extra *key_extra;
17352 httpauth_type type;
17353 } httpauth_keyvalue;
17354 --- ../lighttpd-1.4.11/src/lemon.c 2005-09-01 00:21:34.000000000 +0300
17355 +++ lighttpd-1.5.0/src/lemon.c 2006-07-16 00:26:03.000000000 +0300
17356 @@ -579,7 +579,7 @@
17359 /* Find a precedence symbol of every rule in the grammar.
17362 ** Those rules which have a precedence symbol coded in the input
17363 ** grammar using the "[symbol]" construct will already have the
17364 ** rp->precsym field filled. Other rules take as their precedence
17365 @@ -869,7 +869,7 @@
17366 cfp->status = INCOMPLETE;
17373 for(i=0; i<lemp->nstate; i++){
17374 @@ -900,7 +900,7 @@
17378 - /* Add all of the reduce actions
17379 + /* Add all of the reduce actions
17380 ** A reduce action is added for each element of the followset of
17381 ** a configuration which has its dot at the extreme right.
17383 @@ -1017,7 +1017,7 @@
17384 apx->type = RD_RESOLVED;
17389 apx->type==SH_RESOLVED ||
17390 apx->type==RD_RESOLVED ||
17391 apx->type==CONFLICT ||
17392 @@ -1350,7 +1350,7 @@
17393 OptInit(argv,options,stderr);
17395 printf("Lemon version 1.0\n");
17399 if( OptNArgs() < 1 ){
17400 fprintf(stderr,"Exactly one filename argument is required.\n");
17401 @@ -2031,7 +2031,7 @@
17405 - rp = (struct rule *)malloc( sizeof(struct rule) +
17406 + rp = (struct rule *)malloc( sizeof(struct rule) +
17407 sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs );
17409 ErrorMsg(psp->filename,psp->tokenlineno,
17410 @@ -2546,7 +2546,7 @@
17414 -/* Duplicate the input file without comments and without actions
17415 +/* Duplicate the input file without comments and without actions
17418 struct lemon *lemp;
17419 @@ -2822,7 +2822,7 @@
17420 PRIVATE FILE *tplt_open(lemp)
17421 struct lemon *lemp;
17428 @@ -2930,7 +2930,7 @@
17434 ** Generate code which executes when the rule "rp" is reduced. Write
17435 ** the code to "out". Make sure lineno stays up-to-date.
17437 @@ -3384,7 +3384,7 @@
17439 /* Output the yy_shift_ofst[] table */
17440 fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++;
17441 - fprintf(out, "static %s yy_shift_ofst[] = {\n",
17442 + fprintf(out, "static %s yy_shift_ofst[] = {\n",
17443 minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++;
17445 for(i=j=0; i<n; i++){
17446 @@ -3405,7 +3405,7 @@
17448 /* Output the yy_reduce_ofst[] table */
17449 fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++;
17450 - fprintf(out, "static %s yy_reduce_ofst[] = {\n",
17451 + fprintf(out, "static %s yy_reduce_ofst[] = {\n",
17452 minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++;
17454 for(i=j=0; i<n; i++){
17455 @@ -3480,7 +3480,7 @@
17456 tplt_xfer(lemp->name,in,out,&lineno);
17458 /* Generate code which executes every time a symbol is popped from
17459 - ** the stack while processing errors or while destroying the parser.
17460 + ** the stack while processing errors or while destroying the parser.
17461 ** (In other words, generate the %destructor actions)
17463 if( lemp->tokendest ){
17464 @@ -3522,7 +3522,7 @@
17465 tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno);
17466 tplt_xfer(lemp->name,in,out,&lineno);
17468 - /* Generate the table of rule information
17469 + /* Generate the table of rule information
17471 ** Note: This code depends on the fact that rules are number
17472 ** sequentually beginning with 0.
17473 @@ -3589,7 +3589,7 @@
17474 for(i=1; i<lemp->nterminal; i++){
17475 fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
17482 @@ -3630,7 +3630,7 @@
17488 /* Do not make a default if the number of rules to default
17489 ** is not at least 2 */
17490 if( nbest<2 ) continue;
17491 @@ -3781,7 +3781,7 @@
17495 - x1a->tbl = (x1node*)malloc(
17496 + x1a->tbl = (x1node*)malloc(
17497 (sizeof(x1node) + sizeof(x1node*))*1024 );
17500 @@ -3943,7 +3943,7 @@
17504 - x2a->tbl = (x2node*)malloc(
17505 + x2a->tbl = (x2node*)malloc(
17506 (sizeof(x2node) + sizeof(x2node*))*128 );
17509 @@ -4149,7 +4149,7 @@
17513 - x3a->tbl = (x3node*)malloc(
17514 + x3a->tbl = (x3node*)malloc(
17515 (sizeof(x3node) + sizeof(x3node*))*128 );
17518 @@ -4295,7 +4295,7 @@
17522 - x4a->tbl = (x4node*)malloc(
17523 + x4a->tbl = (x4node*)malloc(
17524 (sizeof(x4node) + sizeof(x4node*))*64 );
17527 --- ../lighttpd-1.4.11/src/lempar.c 2005-08-11 01:26:40.000000000 +0300
17528 +++ lighttpd-1.5.0/src/lempar.c 2006-07-16 00:26:03.000000000 +0300
17530 /* Next is all token values, in a form suitable for use by makeheaders.
17531 ** This section will be null unless lemon is run with the -m switch.
17535 ** These constants (all generated automatically by the parser generator)
17536 ** specify the various kinds of tokens (terminals) that the parser
17540 ** Each symbol here is a terminal symbol in the grammar.
17543 ** and nonterminals. "int" is used otherwise.
17544 ** YYNOCODE is a number of type YYCODETYPE which corresponds
17545 ** to no legal terminal or nonterminal number. This
17546 -** number is used to fill in empty slots of the hash
17547 +** number is used to fill in empty slots of the hash
17549 ** YYFALLBACK If defined, this indicates that one or more tokens
17550 ** have fall-back values which should be used if the
17552 ** and nonterminal numbers. "unsigned char" is
17553 ** used if there are fewer than 250 rules and
17554 ** states combined. "int" is used otherwise.
17555 -** ParseTOKENTYPE is the data type used for minor tokens given
17556 +** ParseTOKENTYPE is the data type used for minor tokens given
17557 ** directly to the parser from the tokenizer.
17558 ** YYMINORTYPE is the data type used for all minor tokens.
17559 ** This is typically a union of many types, one of
17561 /* Next are that tables used to determine what action to take based on the
17562 ** current state and lookahead token. These tables are used to implement
17563 ** functions that take a state number and lookahead value and return an
17564 -** action integer.
17565 +** action integer.
17567 ** Suppose the action integer is N. Then the action is determined as
17570 ** If the index value yy_shift_ofst[S]+X is out of range or if the value
17571 ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
17572 ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
17573 -** and that yy_default[S] should be used instead.
17574 +** and that yy_default[S] should be used instead.
17576 ** The formula above is for computing the action when the lookahead is
17577 ** a terminal symbol. If the lookahead is a non-terminal (as occurs after
17578 @@ -111,7 +111,7 @@
17580 /* The next table maps tokens into fallback tokens. If a construct
17581 ** like the following:
17584 ** %fallback ID X Y Z.
17586 ** appears in the grammer, then ID becomes a fallback token for X, Y,
17587 @@ -163,10 +163,10 @@
17588 #endif /* NDEBUG */
17593 ** Turn parser tracing on by giving a stream to which to write the trace
17594 ** and a prompt to preface each trace message. Tracing is turned off
17595 -** by making either argument NULL
17596 +** by making either argument NULL
17600 @@ -191,7 +191,7 @@
17602 /* For tracing shifts, the names of all terminals and nonterminals
17603 ** are required. The following table supplies these names */
17604 -static const char *yyTokenName[] = {
17605 +static const char *yyTokenName[] = {
17608 #endif /* NDEBUG */
17609 @@ -220,7 +220,7 @@
17615 ** This function allocates a new parser.
17616 ** The only argument is a pointer to a function which works like
17618 @@ -251,7 +251,7 @@
17619 /* Here is inserted the actions which take place when a
17620 ** terminal or non-terminal is destroyed. This can happen
17621 ** when the symbol is popped from the stack during a
17622 - ** reduce or during error processing or when a parser is
17623 + ** reduce or during error processing or when a parser is
17624 ** being destroyed before it is finished parsing.
17626 ** Note: during a reduce, the only symbols destroyed are those
17627 @@ -289,7 +289,7 @@
17633 ** Deallocate and destroy a parser. Destructors are all called for
17634 ** all stack elements before shutting the parser down.
17636 @@ -325,7 +325,7 @@
17639 int stateno = pParser->yystack[pParser->yyidx].stateno;
17642 /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
17643 i = yy_shift_ofst[stateno];
17644 if( i==YY_SHIFT_USE_DFLT ){
17645 @@ -369,7 +369,7 @@
17648 int stateno = pParser->yystack[pParser->yyidx].stateno;
17651 i = yy_reduce_ofst[stateno];
17652 if( i==YY_REDUCE_USE_DFLT ){
17653 return yy_default[stateno];
17654 @@ -455,7 +455,7 @@
17656 yymsp = &yypParser->yystack[yypParser->yyidx];
17658 - if( yyTraceFILE && yyruleno>=0
17659 + if( yyTraceFILE && yyruleno>=0
17660 && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
17661 fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
17662 yyRuleName[yyruleno]);
17663 @@ -608,7 +608,7 @@
17664 #ifdef YYERRORSYMBOL
17665 /* A syntax error has occurred.
17666 ** The response to an error depends upon whether or not the
17667 - ** grammar defines an error token "ERROR".
17668 + ** grammar defines an error token "ERROR".
17670 ** This is what we do if the grammar does define ERROR:
17672 --- ../lighttpd-1.4.11/src/log.c 2005-11-07 15:01:35.000000000 +0200
17673 +++ lighttpd-1.5.0/src/log.c 2006-07-18 13:03:40.000000000 +0300
17678 -#include <unistd.h>
17679 #include <string.h>
17680 #include <stdlib.h>
17683 #include "config.h"
17687 +#undef HAVE_SYSLOG_H
17690 #ifdef HAVE_SYSLOG_H
17691 #include <syslog.h>
17697 +#include "sys-files.h"
17699 #ifdef HAVE_VALGRIND_VALGRIND_H
17700 #include <valgrind/valgrind.h>
17702 @@ -31,55 +36,114 @@
17703 # define O_LARGEFILE 0
17708 * open the errorlog
17711 * we have 3 possibilities:
17712 * - stderr (default)
17718 * if the open failed, report to the user and die
17723 -int log_error_open(server *srv) {
17727 + unsigned short use_syslog;
17729 + /* the errorlog */
17731 - int close_stderr = 1;
17732 + enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } mode;
17735 + time_t cached_ts;
17736 + buffer *cached_ts_str;
17739 +errorlog *myconfig = NULL;
17741 +void log_init(void) {
17745 + err = calloc(1, sizeof(*err));
17748 + err->mode = ERRORLOG_STDERR;
17749 + err->buf = buffer_init();
17750 + err->cached_ts_str = buffer_init();
17755 +void log_free(void) {
17756 + errorlog *err = myconfig;
17758 + if (!err) return;
17760 + TRACE("%s", "server stopped");
17762 + switch(err->mode) {
17763 + case ERRORLOG_FILE:
17766 + case ERRORLOG_SYSLOG:
17767 +#ifdef HAVE_SYSLOG_H
17771 + case ERRORLOG_STDERR:
17775 + buffer_free(err->buf);
17776 + buffer_free(err->cached_ts_str);
17777 + if (err->file) buffer_free(err->file);
17784 +int log_error_open(buffer *file, int use_syslog) {
17786 + int close_stderr = 1;
17788 + errorlog *err = myconfig;
17790 #ifdef HAVE_SYSLOG_H
17791 /* perhaps someone wants to use syslog() */
17792 openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON);
17794 - srv->errorlog_mode = ERRORLOG_STDERR;
17796 - if (srv->srvconf.errorlog_use_syslog) {
17797 - srv->errorlog_mode = ERRORLOG_SYSLOG;
17798 - } else if (!buffer_is_empty(srv->srvconf.errorlog_file)) {
17799 - const char *logfile = srv->srvconf.errorlog_file->ptr;
17801 - if (-1 == (srv->errorlog_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
17802 - log_error_write(srv, __FILE__, __LINE__, "SSSS",
17803 - "opening errorlog '", logfile,
17804 + err->mode = ERRORLOG_STDERR;
17806 + if (use_syslog) {
17807 + err->mode = ERRORLOG_SYSLOG;
17808 + } else if (!buffer_is_empty(file)) {
17809 + if (-1 == (err->fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
17810 + log_error_write(NULL, __FILE__, __LINE__, "SBSS",
17811 + "opening errorlog '", file,
17812 "' failed: ", strerror(errno));
17818 /* close fd on exec (cgi) */
17819 - fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC);
17820 + fcntl(err->fd, F_SETFD, FD_CLOEXEC);
17822 - srv->errorlog_mode = ERRORLOG_FILE;
17823 + err->mode = ERRORLOG_FILE;
17826 - log_error_write(srv, __FILE__, __LINE__, "s", "server started");
17829 + TRACE("%s", "server started");
17831 #ifdef HAVE_VALGRIND_VALGRIND_H
17832 /* don't close stderr for debugging purposes if run in valgrind */
17833 if (RUNNING_ON_VALGRIND) close_stderr = 0;
17835 - if (srv->errorlog_mode == ERRORLOG_STDERR) close_stderr = 0;
17837 + if (err->mode == ERRORLOG_STDERR) close_stderr = 0;
17839 /* move stderr to /dev/null */
17840 if (close_stderr &&
17841 -1 != (fd = open("/dev/null", O_WRONLY))) {
17842 @@ -90,167 +154,202 @@
17848 * open the errorlog
17851 * if the open failed, report to the user and die
17852 * if no filename is given, use syslog instead
17857 -int log_error_cycle(server *srv) {
17858 +int log_error_cycle(void) {
17859 /* only cycle if we are not in syslog-mode */
17861 - if (srv->errorlog_mode == ERRORLOG_FILE) {
17862 - const char *logfile = srv->srvconf.errorlog_file->ptr;
17864 + errorlog *err = myconfig;
17866 + if (err->mode == ERRORLOG_FILE) {
17867 + buffer *file = err->file;
17868 /* already check of opening time */
17873 - if (-1 == (new_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
17875 + if (-1 == (new_fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
17876 /* write to old log */
17877 - log_error_write(srv, __FILE__, __LINE__, "SSSSS",
17878 - "cycling errorlog '", logfile,
17879 + log_error_write(NULL, __FILE__, __LINE__, "SBSSS",
17880 + "cycling errorlog '", file,
17881 "' failed: ", strerror(errno),
17882 ", falling back to syslog()");
17884 - close(srv->errorlog_fd);
17885 - srv->errorlog_fd = -1;
17886 -#ifdef HAVE_SYSLOG_H
17887 - srv->errorlog_mode = ERRORLOG_SYSLOG;
17891 +#ifdef HAVE_SYSLOG_H
17892 + err->mode = ERRORLOG_SYSLOG;
17895 /* ok, new log is open, close the old one */
17896 - close(srv->errorlog_fd);
17897 - srv->errorlog_fd = new_fd;
17899 + err->fd = new_fd;
17903 - log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled");
17908 -int log_error_close(server *srv) {
17909 - log_error_write(srv, __FILE__, __LINE__, "s", "server stopped");
17911 - switch(srv->errorlog_mode) {
17912 - case ERRORLOG_FILE:
17913 - close(srv->errorlog_fd);
17915 - case ERRORLOG_SYSLOG:
17916 -#ifdef HAVE_SYSLOG_H
17920 - case ERRORLOG_STDERR:
17924 + TRACE("%s", "logfiles cycled");
17929 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
17930 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...) {
17933 - switch(srv->errorlog_mode) {
17936 + errorlog *err = myconfig;
17938 + switch(err->mode) {
17939 case ERRORLOG_FILE:
17940 case ERRORLOG_STDERR:
17941 /* cache the generated timestamp */
17942 - if (srv->cur_ts != srv->last_generated_debug_ts) {
17943 - buffer_prepare_copy(srv->ts_debug_str, 255);
17944 - strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
17945 - srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1;
17947 - srv->last_generated_debug_ts = srv->cur_ts;
17950 + if (t != err->cached_ts) {
17951 + buffer_prepare_copy(err->cached_ts_str, 255);
17952 + strftime(err->cached_ts_str->ptr, err->cached_ts_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(t)));
17953 + err->cached_ts_str->used = strlen(err->cached_ts_str->ptr) + 1;
17954 + err->cached_ts = t;
17957 - buffer_copy_string_buffer(srv->errorlog_buf, srv->ts_debug_str);
17958 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ": (");
17959 + buffer_copy_string_buffer(err->buf, err->cached_ts_str);
17960 + BUFFER_APPEND_STRING_CONST(err->buf, ": (");
17962 case ERRORLOG_SYSLOG:
17963 /* syslog is generating its own timestamps */
17964 - BUFFER_COPY_STRING_CONST(srv->errorlog_buf, "(");
17965 + BUFFER_COPY_STRING_CONST(err->buf, "(");
17969 - buffer_append_string(srv->errorlog_buf, filename);
17970 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ".");
17971 - buffer_append_long(srv->errorlog_buf, line);
17972 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ") ");
17976 + buffer_append_string(err->buf, filename);
17977 + BUFFER_APPEND_STRING_CONST(err->buf, ".");
17978 + buffer_append_long(err->buf, line);
17979 + BUFFER_APPEND_STRING_CONST(err->buf, ") ");
17981 for(va_start(ap, fmt); *fmt; fmt++) {
17989 case 's': /* string */
17990 s = va_arg(ap, char *);
17991 - buffer_append_string(srv->errorlog_buf, s);
17992 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
17993 + buffer_append_string(err->buf, s);
17994 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
17996 case 'b': /* buffer */
17997 b = va_arg(ap, buffer *);
17998 - buffer_append_string_buffer(srv->errorlog_buf, b);
17999 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
18000 + buffer_append_string_buffer(err->buf, b);
18001 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
18003 case 'd': /* int */
18004 d = va_arg(ap, int);
18005 - buffer_append_long(srv->errorlog_buf, d);
18006 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
18007 + buffer_append_long(err->buf, d);
18008 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
18010 case 'o': /* off_t */
18011 o = va_arg(ap, off_t);
18012 - buffer_append_off_t(srv->errorlog_buf, o);
18013 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
18014 + buffer_append_off_t(err->buf, o);
18015 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
18017 case 'x': /* int (hex) */
18018 d = va_arg(ap, int);
18019 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "0x");
18020 - buffer_append_long_hex(srv->errorlog_buf, d);
18021 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
18022 + BUFFER_APPEND_STRING_CONST(err->buf, "0x");
18023 + buffer_append_long_hex(err->buf, d);
18024 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
18026 case 'S': /* string */
18027 s = va_arg(ap, char *);
18028 - buffer_append_string(srv->errorlog_buf, s);
18029 + buffer_append_string(err->buf, s);
18031 case 'B': /* buffer */
18032 b = va_arg(ap, buffer *);
18033 - buffer_append_string_buffer(srv->errorlog_buf, b);
18034 + buffer_append_string_buffer(err->buf, b);
18036 case 'D': /* int */
18037 d = va_arg(ap, int);
18038 - buffer_append_long(srv->errorlog_buf, d);
18039 + buffer_append_long(err->buf, d);
18048 - buffer_append_string_len(srv->errorlog_buf, fmt, 1);
18049 + buffer_append_string_len(err->buf, fmt, 1);
18055 - switch(srv->errorlog_mode) {
18057 + switch(err->mode) {
18058 case ERRORLOG_FILE:
18059 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
18060 - write(srv->errorlog_fd, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
18061 + BUFFER_APPEND_STRING_CONST(err->buf, "\n");
18062 + write(err->fd, err->buf->ptr, err->buf->used - 1);
18064 case ERRORLOG_STDERR:
18065 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
18066 - write(STDERR_FILENO, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
18067 + BUFFER_APPEND_STRING_CONST(err->buf, "\n");
18068 + write(STDERR_FILENO, err->buf->ptr, err->buf->used - 1);
18070 +#ifdef HAVE_SYSLOG_H
18071 + case ERRORLOG_SYSLOG:
18072 + syslog(LOG_ERR, "%s", err->buf->ptr);
18080 +static int log_trace_write(const char *fmt, va_list ap) {
18083 + errorlog *err = myconfig;
18085 + b = buffer_init();
18086 + buffer_prepare_copy(b, 1024);
18087 + l = vsnprintf(b->ptr, b->size - 1, fmt, ap);
18089 + b->used = (l > b->size - 1) ? b->size : l + 1;
18093 + switch(err->mode) {
18094 + case ERRORLOG_FILE:
18095 + buffer_append_string(b, "\r\n");
18096 + write(err->fd, b->ptr, b->used - 1);
18098 + case ERRORLOG_STDERR:
18099 + buffer_append_string(b, "\r\n");
18100 + write(STDERR_FILENO, b->ptr, b->used - 1);
18102 +#ifdef HAVE_SYSLOG_H
18103 case ERRORLOG_SYSLOG:
18104 - syslog(LOG_ERR, "%s", srv->errorlog_buf->ptr);
18105 + syslog(LOG_ERR, "%s", b->ptr);
18115 +int log_trace(const char *fmt, ...) {
18118 + va_start(ap, fmt);
18120 + log_trace_write(fmt, ap);
18128 --- ../lighttpd-1.4.11/src/log.h 2005-08-11 01:26:36.000000000 +0300
18129 +++ lighttpd-1.5.0/src/log.h 2006-07-18 13:03:40.000000000 +0300
18134 -#include "server.h"
18135 +#include "buffer.h"
18137 -#define WP() log_error_write(srv, __FILE__, __LINE__, "");
18138 +void log_init(void);
18139 +void log_free(void);
18141 -int log_error_open(server *srv);
18142 -int log_error_close(server *srv);
18143 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...);
18144 -int log_error_cycle(server *srv);
18146 +int log_error_open(buffer *file, int use_syslog);
18147 +int log_error_close();
18148 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...);
18149 +int log_error_cycle();
18151 +#define ERROR(fmt, ...) \
18152 + log_trace("%s.%d: (error) "fmt, __FILE__, __LINE__, __VA_ARGS__)
18154 +#define TRACE(fmt, ...) \
18155 + log_trace("%s.%d: (trace) "fmt, __FILE__, __LINE__, __VA_ARGS__)
18157 +#define SEGFAULT() do { ERROR("%s", "Ooh, Ooh, Ooh. Something is not good ... going down"); abort(); } while(0)
18158 +int log_trace(const char *fmt, ...);
18160 --- ../lighttpd-1.4.11/src/md5.h 2005-11-17 16:20:40.000000000 +0200
18161 +++ lighttpd-1.5.0/src/md5.h 2006-07-16 00:26:04.000000000 +0300
18163 # include <inttypes.h>
18167 +#define UINT4 unsigned __int32
18168 +#define UINT2 unsigned __int16
18169 +#define POINTER unsigned char *
18171 #define UINT4 uint32_t
18172 #define UINT2 uint16_t
18173 #define POINTER unsigned char *
18178 --- ../lighttpd-1.4.11/src/mod_access.c 2006-01-14 19:44:54.000000000 +0200
18179 +++ lighttpd-1.5.0/src/mod_access.c 2006-07-16 00:26:04.000000000 +0300
18180 @@ -8,126 +8,125 @@
18182 #include "plugin.h"
18184 +#include "sys-strings.h"
18187 array *access_deny;
18194 plugin_config **config_storage;
18196 - plugin_config conf;
18198 + plugin_config conf;
18201 INIT_FUNC(mod_access_init) {
18205 p = calloc(1, sizeof(*p));
18211 FREE_FUNC(mod_access_free) {
18212 plugin_data *p = p_d;
18217 if (!p) return HANDLER_GO_ON;
18220 if (p->config_storage) {
18222 for (i = 0; i < srv->config_context->used; i++) {
18223 plugin_config *s = p->config_storage[i];
18226 array_free(s->access_deny);
18231 free(p->config_storage);
18238 return HANDLER_GO_ON;
18241 SETDEFAULTS_FUNC(mod_access_set_defaults) {
18242 plugin_data *p = p_d;
18245 - config_values_t cv[] = {
18247 + config_values_t cv[] = {
18248 { "url.access-deny", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
18249 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
18253 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
18256 for (i = 0; i < srv->config_context->used; i++) {
18260 s = calloc(1, sizeof(plugin_config));
18261 s->access_deny = array_init();
18264 cv[0].destination = s->access_deny;
18267 p->config_storage[i] = s;
18270 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
18271 return HANDLER_ERROR;
18276 return HANDLER_GO_ON;
18279 -#define PATCH(x) \
18280 - p->conf.x = s->x;
18281 static int mod_access_patch_connection(server *srv, connection *con, plugin_data *p) {
18283 plugin_config *s = p->config_storage[0];
18285 - PATCH(access_deny);
18287 + PATCH_OPTION(access_deny);
18289 /* skip the first, the global context */
18290 for (i = 1; i < srv->config_context->used; i++) {
18291 data_config *dc = (data_config *)srv->config_context->data[i];
18292 s = p->config_storage[i];
18295 /* condition didn't match */
18296 if (!config_check_cond(srv, con, dc)) continue;
18300 for (j = 0; j < dc->value->used; j++) {
18301 data_unset *du = dc->value->data[j];
18304 if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.access-deny"))) {
18305 - PATCH(access_deny);
18306 + PATCH_OPTION(access_deny);
18316 URIHANDLER_FUNC(mod_access_uri_handler) {
18317 plugin_data *p = p_d;
18322 if (con->uri.path->used == 0) return HANDLER_GO_ON;
18325 mod_access_patch_connection(srv, con, p);
18328 s_len = con->uri.path->used - 1;
18331 for (k = 0; k < p->conf.access_deny->used; k++) {
18332 data_string *ds = (data_string *)p->conf.access_deny->data[k];
18333 int ct_len = ds->value->used - 1;
18336 if (ct_len > s_len) continue;
18339 if (ds->value->used == 0) continue;
18341 /* if we have a case-insensitive FS we have to lower-case the URI here too */
18342 @@ -135,18 +134,18 @@
18343 if (con->conf.force_lowercase_filenames) {
18344 if (0 == strncasecmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
18345 con->http_status = 403;
18348 return HANDLER_FINISHED;
18351 if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
18352 con->http_status = 403;
18355 return HANDLER_FINISHED;
18362 return HANDLER_GO_ON;
18364 @@ -155,13 +154,13 @@
18365 int mod_access_plugin_init(plugin *p) {
18366 p->version = LIGHTTPD_VERSION_ID;
18367 p->name = buffer_init_string("access");
18370 p->init = mod_access_init;
18371 p->set_defaults = mod_access_set_defaults;
18372 p->handle_uri_clean = mod_access_uri_handler;
18373 p->cleanup = mod_access_free;
18381 --- ../lighttpd-1.4.11/src/mod_accesslog.c 2006-01-31 14:01:43.000000000 +0200
18382 +++ lighttpd-1.5.0/src/mod_accesslog.c 2006-09-07 00:57:05.000000000 +0300
18385 #include <stdlib.h>
18386 #include <string.h>
18387 -#include <fcntl.h>
18388 -#include <unistd.h>
18389 +#include <fcntl.h> /* only the defines on windows */
18394 #include "inet_ntop_cache.h"
18396 #include "sys-socket.h"
18397 +#include "sys-files.h"
18399 #ifdef HAVE_SYSLOG_H
18400 # include <syslog.h>
18408 FORMAT_UNSUPPORTED,
18412 FORMAT_BYTES_OUT_NO_HEADER,
18416 FORMAT_REMOTE_ADDR,
18419 @@ -59,20 +59,20 @@
18420 FORMAT_CONNECTION_STATUS,
18425 FORMAT_RESPONSE_HEADER
18434 * "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
18439 -const format_mapping fmap[] =
18441 +const format_mapping fmap[] =
18443 { '%', FORMAT_PERCENT },
18444 { 'h', FORMAT_REMOTE_HOST },
18445 { 'l', FORMAT_REMOTE_IDENT },
18447 { 's', FORMAT_STATUS },
18448 { 'b', FORMAT_BYTES_OUT_NO_HEADER },
18449 { 'i', FORMAT_HEADER },
18452 { 'a', FORMAT_REMOTE_ADDR },
18453 { 'A', FORMAT_LOCAL_ADDR },
18454 { 'B', FORMAT_BYTES_OUT_NO_HEADER },
18455 @@ -103,23 +103,23 @@
18456 { 'X', FORMAT_CONNECTION_STATUS },
18457 { 'I', FORMAT_BYTES_IN },
18458 { 'O', FORMAT_BYTES_OUT },
18461 { 'o', FORMAT_RESPONSE_HEADER },
18464 { '\0', FORMAT_UNSET }
18469 enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type;
18477 format_field **ptr;
18483 @@ -128,39 +128,39 @@
18484 buffer *access_logfile;
18486 unsigned short use_syslog;
18492 time_t last_generated_accesslog_ts;
18493 time_t *last_generated_accesslog_ts_ptr;
18498 buffer *access_logbuffer;
18499 buffer *ts_accesslog_str;
18502 format_fields *parsed_format;
18509 plugin_config **config_storage;
18510 - plugin_config conf;
18511 + plugin_config conf;
18514 INIT_FUNC(mod_accesslog_init) {
18518 p = calloc(1, sizeof(*p));
18524 int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
18525 size_t i, j, k = 0, start = 0;
18528 for (i = 0; i < format->used - 1; i++) {
18531 switch(format->ptr[i]) {
18534 @@ -173,19 +173,19 @@
18535 fields->size += 16;
18536 fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
18540 fields->ptr[fields->used] = malloc(sizeof(format_fields));
18541 fields->ptr[fields->used]->type = FIELD_STRING;
18542 fields->ptr[fields->used]->string = buffer_init();
18545 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
18554 /* we need a new field */
18557 if (fields->size == 0) {
18560 @@ -194,43 +194,43 @@
18561 fields->size += 16;
18562 fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
18566 /* search for the terminating command */
18567 switch (format->ptr[i+1]) {
18573 for (j = 0; fmap[j].key != '\0'; j++) {
18574 if (fmap[j].key != format->ptr[i+2]) continue;
18580 fields->ptr[fields->used] = malloc(sizeof(format_fields));
18581 fields->ptr[fields->used]->type = FIELD_FORMAT;
18582 fields->ptr[fields->used]->field = fmap[j].type;
18583 fields->ptr[fields->used]->string = NULL;
18593 if (fmap[j].key == '\0') {
18594 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
18604 /* go forward to } */
18607 for (k = i+2; k < format->used - 1; k++) {
18608 if (format->ptr[k] == '}') break;
18612 if (k == format->used - 1) {
18613 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
18615 @@ -239,62 +239,62 @@
18616 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
18621 for (j = 0; fmap[j].key != '\0'; j++) {
18622 if (fmap[j].key != format->ptr[k+1]) continue;
18628 fields->ptr[fields->used] = malloc(sizeof(format_fields));
18629 fields->ptr[fields->used]->type = FIELD_FORMAT;
18630 fields->ptr[fields->used]->field = fmap[j].type;
18631 fields->ptr[fields->used]->string = buffer_init();
18634 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + i + 2, k - (i + 2));
18644 if (fmap[j].key == '\0') {
18645 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
18655 for (j = 0; fmap[j].key != '\0'; j++) {
18656 if (fmap[j].key != format->ptr[i+1]) continue;
18662 fields->ptr[fields->used] = malloc(sizeof(format_fields));
18663 fields->ptr[fields->used]->type = FIELD_FORMAT;
18664 fields->ptr[fields->used]->field = fmap[j].type;
18665 fields->ptr[fields->used]->string = NULL;
18675 if (fmap[j].key == '\0') {
18676 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
18694 /* copy the string */
18695 if (fields->size == 0) {
18696 @@ -305,32 +305,32 @@
18697 fields->size += 16;
18698 fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
18702 fields->ptr[fields->used] = malloc(sizeof(format_fields));
18703 fields->ptr[fields->used]->type = FIELD_STRING;
18704 fields->ptr[fields->used]->string = buffer_init();
18707 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
18717 FREE_FUNC(mod_accesslog_free) {
18718 plugin_data *p = p_d;
18722 if (!p) return HANDLER_GO_ON;
18725 if (p->config_storage) {
18728 for (i = 0; i < srv->config_context->used; i++) {
18729 plugin_config *s = p->config_storage[i];
18734 if (s->access_logbuffer->used) {
18735 if (s->use_syslog) {
18736 # ifdef HAVE_SYSLOG_H
18737 @@ -342,14 +342,14 @@
18738 write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
18743 if (s->log_access_fd != -1) close(s->log_access_fd);
18746 buffer_free(s->ts_accesslog_str);
18747 buffer_free(s->access_logbuffer);
18748 buffer_free(s->format);
18749 buffer_free(s->access_logfile);
18752 if (s->parsed_format) {
18754 for (j = 0; j < s->parsed_format->used; j++) {
18755 @@ -359,36 +359,36 @@
18756 free(s->parsed_format->ptr);
18757 free(s->parsed_format);
18765 free(p->config_storage);
18772 return HANDLER_GO_ON;
18775 SETDEFAULTS_FUNC(log_access_open) {
18776 plugin_data *p = p_d;
18779 - config_values_t cv[] = {
18781 + config_values_t cv[] = {
18782 { "accesslog.filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
18783 { "accesslog.use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
18784 { "accesslog.format", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
18785 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
18789 if (!p) return HANDLER_ERROR;
18792 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
18795 for (i = 0; i < srv->config_context->used; i++) {
18799 s = calloc(1, sizeof(plugin_config));
18800 s->access_logfile = buffer_init();
18801 s->format = buffer_init();
18802 @@ -397,44 +397,44 @@
18803 s->log_access_fd = -1;
18804 s->last_generated_accesslog_ts = 0;
18805 s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts);
18810 cv[0].destination = s->access_logfile;
18811 cv[1].destination = &(s->use_syslog);
18812 cv[2].destination = s->format;
18815 p->config_storage[i] = s;
18818 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
18819 return HANDLER_ERROR;
18823 if (i == 0 && buffer_is_empty(s->format)) {
18824 /* set a default logfile string */
18827 buffer_copy_string(s->format, "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"");
18834 if (s->format->used) {
18835 s->parsed_format = calloc(1, sizeof(*(s->parsed_format)));
18838 if (-1 == accesslog_parse_format(srv, s->parsed_format, s->format)) {
18840 - log_error_write(srv, __FILE__, __LINE__, "sb",
18841 + log_error_write(srv, __FILE__, __LINE__, "sb",
18842 "parsing accesslog-definition failed:", s->format);
18844 return HANDLER_ERROR;
18849 for (j = 0; j < s->parsed_format->used; j++) {
18850 switch (s->parsed_format->ptr[j]->type) {
18852 - log_error_write(srv, __FILE__, __LINE__, "ssds",
18853 + log_error_write(srv, __FILE__, __LINE__, "ssds",
18854 "config:", "format", s->parsed_format->ptr[j]->field,
18855 - s->parsed_format->ptr[j]->string ?
18856 + s->parsed_format->ptr[j]->string ?
18857 s->parsed_format->ptr[j]->string->ptr : "" );
18860 @@ -446,52 +446,52 @@
18866 if (s->use_syslog) {
18867 /* ignore the next checks */
18872 if (buffer_is_empty(s->access_logfile)) continue;
18875 if (s->access_logfile->ptr[0] == '|') {
18877 /* create write pipe and spawn process */
18884 if (pipe(to_log_fds)) {
18885 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
18886 return HANDLER_ERROR;
18891 switch (pid = fork()) {
18897 close(STDIN_FILENO);
18898 dup2(to_log_fds[0], STDIN_FILENO);
18899 close(to_log_fds[0]);
18901 close(to_log_fds[1]);
18904 /* we don't need the client socket */
18905 for (i = 3; i < 256; i++) {
18909 - /* exec the log-process (skip the | )
18912 + /* exec the log-process (skip the | )
18917 execl("/bin/sh", "sh", "-c", s->access_logfile->ptr + 1, NULL);
18919 - log_error_write(srv, __FILE__, __LINE__, "sss",
18920 - "spawning log-process failed: ", strerror(errno),
18921 + log_error_write(srv, __FILE__, __LINE__, "sss",
18922 + "spawning log-process failed: ", strerror(errno),
18923 s->access_logfile->ptr + 1);
18929 @@ -500,27 +500,28 @@
18932 close(to_log_fds[0]);
18935 s->log_access_fd = to_log_fds[1];
18943 - } else if (-1 == (s->log_access_fd =
18944 + } else if (-1 == (s->log_access_fd =
18945 open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
18947 - log_error_write(srv, __FILE__, __LINE__, "ssb",
18948 - "opening access-log failed:",
18950 + log_error_write(srv, __FILE__, __LINE__, "ssb",
18951 + "opening access-log failed:",
18952 strerror(errno), s->access_logfile);
18955 return HANDLER_ERROR;
18958 fcntl(s->log_access_fd, F_SETFD, FD_CLOEXEC);
18964 return HANDLER_GO_ON;
18967 @@ -529,7 +530,7 @@
18970 if (!p->config_storage) return HANDLER_GO_ON;
18973 for (i = 0; i < srv->config_context->used; i++) {
18974 plugin_config *s = p->config_storage[i];
18976 @@ -544,90 +545,87 @@
18977 } else if (s->log_access_fd != -1) {
18978 write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
18982 buffer_reset(s->access_logbuffer);
18986 if (s->use_syslog == 0 &&
18987 !buffer_is_empty(s->access_logfile) &&
18988 s->access_logfile->ptr[0] != '|') {
18991 close(s->log_access_fd);
18993 - if (-1 == (s->log_access_fd =
18995 + if (-1 == (s->log_access_fd =
18996 open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
18999 log_error_write(srv, __FILE__, __LINE__, "ss", "cycling access-log failed:", strerror(errno));
19002 return HANDLER_ERROR;
19008 return HANDLER_GO_ON;
19011 -#define PATCH(x) \
19012 - p->conf.x = s->x;
19013 static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_data *p) {
19015 plugin_config *s = p->config_storage[0];
19017 - PATCH(access_logfile);
19019 - PATCH(log_access_fd);
19020 - PATCH(last_generated_accesslog_ts_ptr);
19021 - PATCH(access_logbuffer);
19022 - PATCH(ts_accesslog_str);
19023 - PATCH(parsed_format);
19024 - PATCH(use_syslog);
19027 + PATCH_OPTION(access_logfile);
19028 + PATCH_OPTION(format);
19029 + PATCH_OPTION(log_access_fd);
19030 + PATCH_OPTION(last_generated_accesslog_ts_ptr);
19031 + PATCH_OPTION(access_logbuffer);
19032 + PATCH_OPTION(ts_accesslog_str);
19033 + PATCH_OPTION(parsed_format);
19034 + PATCH_OPTION(use_syslog);
19036 /* skip the first, the global context */
19037 for (i = 1; i < srv->config_context->used; i++) {
19038 data_config *dc = (data_config *)srv->config_context->data[i];
19039 s = p->config_storage[i];
19042 /* condition didn't match */
19043 if (!config_check_cond(srv, con, dc)) continue;
19047 for (j = 0; j < dc->value->used; j++) {
19048 data_unset *du = dc->value->data[j];
19051 if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.filename"))) {
19052 - PATCH(access_logfile);
19053 - PATCH(log_access_fd);
19054 - PATCH(last_generated_accesslog_ts_ptr);
19055 - PATCH(access_logbuffer);
19056 - PATCH(ts_accesslog_str);
19057 + PATCH_OPTION(access_logfile);
19058 + PATCH_OPTION(log_access_fd);
19059 + PATCH_OPTION(last_generated_accesslog_ts_ptr);
19060 + PATCH_OPTION(access_logbuffer);
19061 + PATCH_OPTION(ts_accesslog_str);
19062 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.format"))) {
19064 - PATCH(parsed_format);
19065 + PATCH_OPTION(format);
19066 + PATCH_OPTION(parsed_format);
19067 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.use-syslog"))) {
19068 - PATCH(use_syslog);
19069 + PATCH_OPTION(use_syslog);
19079 REQUESTDONE_FUNC(log_access_write) {
19080 plugin_data *p = p_d;
19089 mod_accesslog_patch_connection(srv, con, p);
19092 b = p->conf.access_logbuffer;
19093 if (b->used == 0) {
19094 buffer_copy_string(b, "");
19098 for (j = 0; j < p->conf.parsed_format->used; j++) {
19099 switch(p->conf.parsed_format->ptr[j]->type) {
19101 @@ -636,14 +634,14 @@
19103 switch(p->conf.parsed_format->ptr[j]->field) {
19104 case FORMAT_TIMESTAMP:
19107 /* cache the generated timestamp */
19108 if (srv->cur_ts != *(p->conf.last_generated_accesslog_ts_ptr)) {
19110 #if defined(HAVE_STRUCT_TM_GMTOFF)
19111 long scd, hrs, min;
19115 buffer_prepare_copy(p->conf.ts_accesslog_str, 255);
19116 #if defined(HAVE_STRUCT_TM_GMTOFF)
19117 # ifdef HAVE_LOCALTIME_R
19118 @@ -653,17 +651,17 @@
19119 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)));
19121 p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
19124 buffer_append_string(p->conf.ts_accesslog_str, tm.tm_gmtoff >= 0 ? "+" : "-");
19127 scd = abs(tm.tm_gmtoff);
19129 min = (scd % 3600) / 60;
19133 if (hrs < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
19134 buffer_append_long(p->conf.ts_accesslog_str, hrs);
19137 if (min < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
19138 buffer_append_long(p->conf.ts_accesslog_str, min);
19139 BUFFER_APPEND_STRING_CONST(p->conf.ts_accesslog_str, "]");
19140 @@ -676,20 +674,20 @@
19142 p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
19146 *(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts;
19151 buffer_append_string_buffer(b, p->conf.ts_accesslog_str);
19155 case FORMAT_REMOTE_HOST:
19158 /* handle inet_ntop cache */
19161 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
19165 case FORMAT_REMOTE_IDENT:
19167 @@ -703,17 +701,20 @@
19170 case FORMAT_REQUEST_LINE:
19171 - if (con->request.request_line->used) {
19172 - buffer_append_string_buffer(b, con->request.request_line);
19174 + buffer_append_string(b, get_http_method_name(con->request.http_method));
19175 + buffer_append_string(b, " ");
19176 + buffer_append_string_buffer(b, con->request.orig_uri);
19177 + buffer_append_string(b, " ");
19178 + buffer_append_string(b, get_http_version_name(con->request.http_version));
19181 case FORMAT_STATUS:
19182 buffer_append_long(b, con->http_status);
19186 case FORMAT_BYTES_OUT_NO_HEADER:
19187 if (con->bytes_written > 0) {
19188 - buffer_append_off_t(b,
19189 + buffer_append_off_t(b,
19190 con->bytes_written - con->bytes_header <= 0 ? 0 : con->bytes_written - con->bytes_header);
19192 BUFFER_APPEND_STRING_CONST(b, "-");
19193 @@ -772,7 +773,7 @@
19196 case FORMAT_REQUEST_PROTOCOL:
19197 - buffer_append_string(b,
19198 + buffer_append_string(b,
19199 con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0");
19201 case FORMAT_REQUEST_METHOD:
19202 @@ -801,7 +802,7 @@
19203 { 'D', FORMAT_TIME_USED_MS },
19204 { 'e', FORMAT_ENV },
19211 @@ -809,7 +810,7 @@
19217 BUFFER_APPEND_STRING_CONST(b, "\n");
19219 if (p->conf.use_syslog || /* syslog doesn't cache */
19220 @@ -828,7 +829,7 @@
19226 return HANDLER_GO_ON;
19229 @@ -836,15 +837,15 @@
19230 int mod_accesslog_plugin_init(plugin *p) {
19231 p->version = LIGHTTPD_VERSION_ID;
19232 p->name = buffer_init_string("accesslog");
19235 p->init = mod_accesslog_init;
19236 p->set_defaults= log_access_open;
19237 p->cleanup = mod_accesslog_free;
19239 - p->handle_request_done = log_access_write;
19240 - p->handle_sighup = log_access_cycle;
19243 + p->handle_response_done = log_access_write;
19244 + p->handle_sighup = log_access_cycle;
19251 --- ../lighttpd-1.4.11/src/mod_alias.c 2006-03-01 23:18:51.000000000 +0200
19252 +++ lighttpd-1.5.0/src/mod_alias.c 2006-07-16 00:26:03.000000000 +0300
19254 #include "buffer.h"
19256 #include "plugin.h"
19257 +#include "sys-strings.h"
19259 /* plugin config for all request/connections */
19261 @@ -16,44 +17,44 @@
19267 plugin_config **config_storage;
19269 - plugin_config conf;
19271 + plugin_config conf;
19274 /* init the plugin data */
19275 INIT_FUNC(mod_alias_init) {
19279 p = calloc(1, sizeof(*p));
19289 /* detroy the plugin data */
19290 FREE_FUNC(mod_alias_free) {
19291 plugin_data *p = p_d;
19294 if (!p) return HANDLER_GO_ON;
19297 if (p->config_storage) {
19301 for (i = 0; i < srv->config_context->used; i++) {
19302 plugin_config *s = p->config_storage[i];
19305 array_free(s->alias);
19310 free(p->config_storage);
19317 return HANDLER_GO_ON;
19320 @@ -62,25 +63,25 @@
19321 SETDEFAULTS_FUNC(mod_alias_set_defaults) {
19322 plugin_data *p = p_d;
19325 - config_values_t cv[] = {
19327 + config_values_t cv[] = {
19328 { "alias.url", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
19329 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
19333 if (!p) return HANDLER_ERROR;
19336 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
19339 for (i = 0; i < srv->config_context->used; i++) {
19343 s = calloc(1, sizeof(plugin_config));
19344 - s->alias = array_init();
19345 + s->alias = array_init();
19346 cv[0].destination = s->alias;
19349 p->config_storage[i] = s;
19352 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
19353 return HANDLER_ERROR;
19355 @@ -110,76 +111,73 @@
19361 return HANDLER_GO_ON;
19364 -#define PATCH(x) \
19365 - p->conf.x = s->x;
19366 static int mod_alias_patch_connection(server *srv, connection *con, plugin_data *p) {
19368 plugin_config *s = p->config_storage[0];
19373 + PATCH_OPTION(alias);
19375 /* skip the first, the global context */
19376 for (i = 1; i < srv->config_context->used; i++) {
19377 data_config *dc = (data_config *)srv->config_context->data[i];
19378 s = p->config_storage[i];
19381 /* condition didn't match */
19382 if (!config_check_cond(srv, con, dc)) continue;
19386 for (j = 0; j < dc->value->used; j++) {
19387 data_unset *du = dc->value->data[j];
19390 if (buffer_is_equal_string(du->key, CONST_STR_LEN("alias.url"))) {
19392 + PATCH_OPTION(alias);
19402 PHYSICALPATH_FUNC(mod_alias_physical_handler) {
19403 plugin_data *p = p_d;
19404 int uri_len, basedir_len;
19409 if (con->physical.path->used == 0) return HANDLER_GO_ON;
19412 mod_alias_patch_connection(srv, con, p);
19415 /* not to include the tailing slash */
19416 basedir_len = (con->physical.basedir->used - 1) - 1;
19417 uri_len = con->physical.path->used - 1 - basedir_len;
19418 uri_ptr = con->physical.path->ptr + basedir_len;
19421 for (k = 0; k < p->conf.alias->used; k++) {
19422 data_string *ds = (data_string *)p->conf.alias->data[k];
19423 int alias_len = ds->key->used - 1;
19426 if (alias_len > uri_len) continue;
19427 if (ds->key->used == 0) continue;
19430 if (0 == (con->conf.force_lowercase_filenames ?
19431 strncasecmp(uri_ptr, ds->key->ptr, alias_len) :
19432 strncmp(uri_ptr, ds->key->ptr, alias_len))) {
19436 buffer_copy_string_buffer(con->physical.basedir, ds->value);
19437 buffer_copy_string_buffer(srv->tmp_buf, ds->value);
19438 buffer_append_string(srv->tmp_buf, uri_ptr + alias_len);
19439 buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
19442 return HANDLER_GO_ON;
19448 return HANDLER_GO_ON;
19450 @@ -189,13 +187,13 @@
19451 int mod_alias_plugin_init(plugin *p) {
19452 p->version = LIGHTTPD_VERSION_ID;
19453 p->name = buffer_init_string("alias");
19456 p->init = mod_alias_init;
19457 p->handle_physical= mod_alias_physical_handler;
19458 p->set_defaults = mod_alias_set_defaults;
19459 p->cleanup = mod_alias_free;
19467 --- ../lighttpd-1.4.11/src/mod_auth.c 2006-02-15 20:01:31.000000000 +0200
19468 +++ lighttpd-1.5.0/src/mod_auth.c 2006-07-18 13:03:40.000000000 +0300
19469 @@ -5,168 +5,167 @@
19470 #include <string.h>
19473 -#include <unistd.h>
19475 #include "plugin.h"
19476 #include "http_auth.h"
19478 #include "response.h"
19480 +#include "sys-strings.h"
19481 +#include "sys-files.h"
19483 handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
19487 * the basic and digest auth framework
19490 * - config handling
19491 * - protocol handling
19494 - * http_auth_digest.c
19498 + * http_auth_digest.c
19503 INIT_FUNC(mod_auth_init) {
19504 mod_auth_plugin_data *p;
19507 p = calloc(1, sizeof(*p));
19510 p->tmp_buf = buffer_init();
19513 p->auth_user = buffer_init();
19515 p->ldap_filter = buffer_init();
19522 FREE_FUNC(mod_auth_free) {
19523 mod_auth_plugin_data *p = p_d;
19528 if (!p) return HANDLER_GO_ON;
19531 buffer_free(p->tmp_buf);
19532 buffer_free(p->auth_user);
19534 buffer_free(p->ldap_filter);
19538 if (p->config_storage) {
19540 for (i = 0; i < srv->config_context->used; i++) {
19541 mod_auth_plugin_config *s = p->config_storage[i];
19547 array_free(s->auth_require);
19548 buffer_free(s->auth_plain_groupfile);
19549 buffer_free(s->auth_plain_userfile);
19550 buffer_free(s->auth_htdigest_userfile);
19551 buffer_free(s->auth_htpasswd_userfile);
19552 buffer_free(s->auth_backend_conf);
19555 buffer_free(s->auth_ldap_hostname);
19556 buffer_free(s->auth_ldap_basedn);
19557 buffer_free(s->auth_ldap_binddn);
19558 buffer_free(s->auth_ldap_bindpw);
19559 buffer_free(s->auth_ldap_filter);
19560 buffer_free(s->auth_ldap_cafile);
19564 buffer_free(s->ldap_filter_pre);
19565 buffer_free(s->ldap_filter_post);
19568 if (s->ldap) ldap_unbind_s(s->ldap);
19574 free(p->config_storage);
19581 return HANDLER_GO_ON;
19584 -#define PATCH(x) \
19585 - p->conf.x = s->x;
19586 static int mod_auth_patch_connection(server *srv, connection *con, mod_auth_plugin_data *p) {
19588 mod_auth_plugin_config *s = p->config_storage[0];
19590 - PATCH(auth_backend);
19591 - PATCH(auth_plain_groupfile);
19592 - PATCH(auth_plain_userfile);
19593 - PATCH(auth_htdigest_userfile);
19594 - PATCH(auth_htpasswd_userfile);
19595 - PATCH(auth_require);
19596 - PATCH(auth_debug);
19597 - PATCH(auth_ldap_hostname);
19598 - PATCH(auth_ldap_basedn);
19599 - PATCH(auth_ldap_binddn);
19600 - PATCH(auth_ldap_bindpw);
19601 - PATCH(auth_ldap_filter);
19602 - PATCH(auth_ldap_cafile);
19603 - PATCH(auth_ldap_starttls);
19604 + PATCH_OPTION(auth_backend);
19605 + PATCH_OPTION(auth_plain_groupfile);
19606 + PATCH_OPTION(auth_plain_userfile);
19607 + PATCH_OPTION(auth_htdigest_userfile);
19608 + PATCH_OPTION(auth_htpasswd_userfile);
19609 + PATCH_OPTION(auth_require);
19610 + PATCH_OPTION(auth_debug);
19611 + PATCH_OPTION(auth_ldap_hostname);
19612 + PATCH_OPTION(auth_ldap_basedn);
19613 + PATCH_OPTION(auth_ldap_binddn);
19614 + PATCH_OPTION(auth_ldap_bindpw);
19615 + PATCH_OPTION(auth_ldap_filter);
19616 + PATCH_OPTION(auth_ldap_cafile);
19617 + PATCH_OPTION(auth_ldap_starttls);
19620 - PATCH(ldap_filter_pre);
19621 - PATCH(ldap_filter_post);
19622 + PATCH_OPTION(ldap);
19623 + PATCH_OPTION(ldap_filter_pre);
19624 + PATCH_OPTION(ldap_filter_post);
19628 /* skip the first, the global context */
19629 for (i = 1; i < srv->config_context->used; i++) {
19630 data_config *dc = (data_config *)srv->config_context->data[i];
19631 s = p->config_storage[i];
19634 /* condition didn't match */
19635 if (!config_check_cond(srv, con, dc)) continue;
19639 for (j = 0; j < dc->value->used; j++) {
19640 data_unset *du = dc->value->data[j];
19643 if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend"))) {
19644 - PATCH(auth_backend);
19645 + PATCH_OPTION(auth_backend);
19646 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.groupfile"))) {
19647 - PATCH(auth_plain_groupfile);
19648 + PATCH_OPTION(auth_plain_groupfile);
19649 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.userfile"))) {
19650 - PATCH(auth_plain_userfile);
19651 + PATCH_OPTION(auth_plain_userfile);
19652 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htdigest.userfile"))) {
19653 - PATCH(auth_htdigest_userfile);
19654 + PATCH_OPTION(auth_htdigest_userfile);
19655 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htpasswd.userfile"))) {
19656 - PATCH(auth_htpasswd_userfile);
19657 + PATCH_OPTION(auth_htpasswd_userfile);
19658 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.require"))) {
19659 - PATCH(auth_require);
19660 + PATCH_OPTION(auth_require);
19661 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.debug"))) {
19662 - PATCH(auth_debug);
19663 + PATCH_OPTION(auth_debug);
19664 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.hostname"))) {
19665 - PATCH(auth_ldap_hostname);
19666 + PATCH_OPTION(auth_ldap_hostname);
19669 - PATCH(ldap_filter_pre);
19670 - PATCH(ldap_filter_post);
19671 + PATCH_OPTION(ldap);
19672 + PATCH_OPTION(ldap_filter_pre);
19673 + PATCH_OPTION(ldap_filter_post);
19675 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.base-dn"))) {
19676 - PATCH(auth_ldap_basedn);
19677 + PATCH_OPTION(auth_ldap_basedn);
19678 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) {
19679 - PATCH(auth_ldap_filter);
19680 + PATCH_OPTION(auth_ldap_filter);
19681 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.ca-file"))) {
19682 - PATCH(auth_ldap_cafile);
19683 + PATCH_OPTION(auth_ldap_cafile);
19684 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.starttls"))) {
19685 - PATCH(auth_ldap_starttls);
19686 + PATCH_OPTION(auth_ldap_starttls);
19696 static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
19698 @@ -175,22 +174,22 @@
19700 mod_auth_plugin_data *p = p_d;
19704 /* select the right config */
19705 mod_auth_patch_connection(srv, con, p);
19708 if (p->conf.auth_require == NULL) return HANDLER_GO_ON;
19718 /* do we have to ask for auth ? */
19722 auth_satisfied = 0;
19725 /* search auth-directives for path */
19726 for (k = 0; k < p->conf.auth_require->used; k++) {
19727 buffer *req = p->conf.auth_require->data[k]->key;
19728 @@ -212,76 +211,76 @@
19734 /* nothing to do for us */
19735 if (auth_required == 0) return HANDLER_GO_ON;
19738 req = ((data_array *)(p->conf.auth_require->data[k]))->value;
19741 /* try to get Authorization-header */
19744 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization"))) {
19745 http_authorization = ds->value->ptr;
19749 if (ds && ds->value && ds->value->used) {
19751 data_string *method;
19754 method = (data_string *)array_get_element(req, "method");
19757 /* parse auth-header */
19758 if (NULL != (auth_realm = strchr(http_authorization, ' '))) {
19759 int auth_type_len = auth_realm - http_authorization;
19762 if ((auth_type_len == 5) &&
19763 (0 == strncmp(http_authorization, "Basic", auth_type_len))) {
19765 - if (0 == strcmp(method->value->ptr, "basic")) {
19767 + if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
19768 auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1);
19770 } else if ((auth_type_len == 6) &&
19771 (0 == strncmp(http_authorization, "Digest", auth_type_len))) {
19772 - if (0 == strcmp(method->value->ptr, "digest")) {
19773 + if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
19774 if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) {
19775 con->http_status = 400;
19778 /* a field was missing */
19781 return HANDLER_FINISHED;
19785 - log_error_write(srv, __FILE__, __LINE__, "ss",
19786 + log_error_write(srv, __FILE__, __LINE__, "ss",
19787 "unknown authentification type:",
19788 http_authorization);
19794 if (!auth_satisfied) {
19795 data_string *method, *realm;
19796 method = (data_string *)array_get_element(req, "method");
19797 realm = (data_string *)array_get_element(req, "realm");
19800 con->http_status = 401;
19802 - if (0 == strcmp(method->value->ptr, "basic")) {
19804 + if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
19805 buffer_copy_string(p->tmp_buf, "Basic realm=\"");
19806 buffer_append_string_buffer(p->tmp_buf, realm->value);
19807 buffer_append_string(p->tmp_buf, "\"");
19810 response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
19811 - } else if (0 == strcmp(method->value->ptr, "digest")) {
19812 + } else if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
19814 http_auth_digest_generate_nonce(srv, p, srv->tmp_buf, hh);
19817 buffer_copy_string(p->tmp_buf, "Digest realm=\"");
19818 buffer_append_string_buffer(p->tmp_buf, realm->value);
19819 buffer_append_string(p->tmp_buf, "\", nonce=\"");
19820 buffer_append_string(p->tmp_buf, hh);
19821 buffer_append_string(p->tmp_buf, "\", qop=\"auth\"");
19824 response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
19827 @@ -289,18 +288,18 @@
19828 return HANDLER_FINISHED;
19830 /* the REMOTE_USER header */
19833 buffer_copy_string_buffer(con->authed_user, p->auth_user);
19837 return HANDLER_GO_ON;
19840 SETDEFAULTS_FUNC(mod_auth_set_defaults) {
19841 mod_auth_plugin_data *p = p_d;
19844 - config_values_t cv[] = {
19846 + config_values_t cv[] = {
19847 { "auth.backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
19848 { "auth.backend.plain.groupfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
19849 { "auth.backend.plain.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
19850 @@ -317,7 +316,7 @@
19851 { "auth.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
19852 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
19856 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
19858 for (i = 0; i < srv->config_context->used; i++) {
19859 @@ -325,14 +324,14 @@
19865 s = calloc(1, sizeof(mod_auth_plugin_config));
19866 s->auth_plain_groupfile = buffer_init();
19867 s->auth_plain_userfile = buffer_init();
19868 s->auth_htdigest_userfile = buffer_init();
19869 s->auth_htpasswd_userfile = buffer_init();
19870 s->auth_backend_conf = buffer_init();
19873 s->auth_ldap_hostname = buffer_init();
19874 s->auth_ldap_basedn = buffer_init();
19875 s->auth_ldap_binddn = buffer_init();
19876 @@ -341,15 +340,15 @@
19877 s->auth_ldap_cafile = buffer_init();
19878 s->auth_ldap_starttls = 0;
19882 s->auth_require = array_init();
19886 s->ldap_filter_pre = buffer_init();
19887 s->ldap_filter_post = buffer_init();
19892 cv[0].destination = s->auth_backend_conf;
19893 cv[1].destination = s->auth_plain_groupfile;
19894 cv[2].destination = s->auth_plain_userfile;
19895 @@ -364,146 +363,148 @@
19896 cv[11].destination = s->auth_htdigest_userfile;
19897 cv[12].destination = s->auth_htpasswd_userfile;
19898 cv[13].destination = &(s->auth_debug);
19901 p->config_storage[i] = s;
19902 ca = ((data_config *)srv->config_context->data[i])->value;
19905 if (0 != config_insert_values_global(srv, ca, cv)) {
19906 return HANDLER_ERROR;
19909 - if (s->auth_backend_conf->used) {
19910 - if (0 == strcmp(s->auth_backend_conf->ptr, "htpasswd")) {
19912 + if (!buffer_is_empty(s->auth_backend_conf)) {
19913 + if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htpasswd"))) {
19914 s->auth_backend = AUTH_BACKEND_HTPASSWD;
19915 - } else if (0 == strcmp(s->auth_backend_conf->ptr, "htdigest")) {
19916 + } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htdigest"))) {
19917 s->auth_backend = AUTH_BACKEND_HTDIGEST;
19918 - } else if (0 == strcmp(s->auth_backend_conf->ptr, "plain")) {
19919 + } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("plain"))) {
19920 s->auth_backend = AUTH_BACKEND_PLAIN;
19921 - } else if (0 == strcmp(s->auth_backend_conf->ptr, "ldap")) {
19922 + } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("ldap"))) {
19923 s->auth_backend = AUTH_BACKEND_LDAP;
19925 log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf);
19928 return HANDLER_ERROR;
19932 /* no auth.require for this section */
19933 if (NULL == (da = (data_array *)array_get_element(ca, "auth.require"))) continue;
19936 if (da->type != TYPE_ARRAY) continue;
19939 for (n = 0; n < da->value->used; n++) {
19941 data_array *da_file = (data_array *)da->value->data[n];
19942 - const char *method, *realm, *require;
19944 + buffer *method, *realm, *require;
19946 if (da->value->data[n]->type != TYPE_ARRAY) {
19947 - log_error_write(srv, __FILE__, __LINE__, "ss",
19948 - "auth.require should contain an array as in:",
19949 + log_error_write(srv, __FILE__, __LINE__, "ss",
19950 + "auth.require should contain an array as in:",
19951 "auth.require = ( \"...\" => ( ..., ...) )");
19953 return HANDLER_ERROR;
19957 method = realm = require = NULL;
19960 for (m = 0; m < da_file->value->used; m++) {
19961 - if (da_file->value->data[m]->type == TYPE_STRING) {
19962 - if (0 == strcmp(da_file->value->data[m]->key->ptr, "method")) {
19963 - method = ((data_string *)(da_file->value->data[m]))->value->ptr;
19964 - } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "realm")) {
19965 - realm = ((data_string *)(da_file->value->data[m]))->value->ptr;
19966 - } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "require")) {
19967 - require = ((data_string *)(da_file->value->data[m]))->value->ptr;
19969 - log_error_write(srv, __FILE__, __LINE__, "ssbs",
19970 - "the field is unknown in:",
19971 + data_string *ds_auth_req = (data_string *)da_file->value->data[m];
19973 + if (ds_auth_req->type != TYPE_STRING) {
19974 + log_error_write(srv, __FILE__, __LINE__, "ssbs",
19975 + "a string was expected for:",
19976 + "auth.require = ( \"...\" => ( ..., -> \"",
19977 + ds_auth_req->key,
19978 + "\" <- => \"...\" ) )");
19980 + return HANDLER_ERROR;
19983 + if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("method"))) {
19984 + method = ds_auth_req->value;
19985 + } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("realm"))) {
19986 + realm = ds_auth_req->value;
19987 + } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("require"))) {
19988 + require = ds_auth_req->value;
19990 + log_error_write(srv, __FILE__, __LINE__, "ssbs",
19991 + "the field is unknown in:",
19992 "auth.require = ( \"...\" => ( ..., -> \"",
19993 da_file->value->data[m]->key,
19994 "\" <- => \"...\" ) )");
19996 - return HANDLER_ERROR;
19999 - log_error_write(srv, __FILE__, __LINE__, "ssbs",
20000 - "a string was expected for:",
20001 - "auth.require = ( \"...\" => ( ..., -> \"",
20002 - da_file->value->data[m]->key,
20003 - "\" <- => \"...\" ) )");
20005 return HANDLER_ERROR;
20011 if (method == NULL) {
20012 - log_error_write(srv, __FILE__, __LINE__, "ss",
20013 - "the require field is missing in:",
20014 + log_error_write(srv, __FILE__, __LINE__, "ss",
20015 + "the require field is missing in:",
20016 "auth.require = ( \"...\" => ( ..., \"method\" => \"...\" ) )");
20017 return HANDLER_ERROR;
20019 - if (0 != strcmp(method, "basic") &&
20020 - 0 != strcmp(method, "digest")) {
20021 - log_error_write(srv, __FILE__, __LINE__, "ss",
20022 - "method has to be either \"basic\" or \"digest\" in",
20023 - "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
20024 - return HANDLER_ERROR;
20027 + if (!buffer_is_equal_string(method, CONST_STR_LEN("basic")) &&
20028 + !buffer_is_equal_string(method, CONST_STR_LEN("digest"))) {
20029 + log_error_write(srv, __FILE__, __LINE__, "ss",
20030 + "method has to be either \"basic\" or \"digest\" in",
20031 + "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
20032 + return HANDLER_ERROR;
20036 if (realm == NULL) {
20037 - log_error_write(srv, __FILE__, __LINE__, "ss",
20038 - "the require field is missing in:",
20039 + log_error_write(srv, __FILE__, __LINE__, "ss",
20040 + "the require field is missing in:",
20041 "auth.require = ( \"...\" => ( ..., \"realm\" => \"...\" ) )");
20042 return HANDLER_ERROR;
20046 if (require == NULL) {
20047 - log_error_write(srv, __FILE__, __LINE__, "ss",
20048 - "the require field is missing in:",
20049 + log_error_write(srv, __FILE__, __LINE__, "ss",
20050 + "the require field is missing in:",
20051 "auth.require = ( \"...\" => ( ..., \"require\" => \"...\" ) )");
20052 return HANDLER_ERROR;
20056 if (method && realm && require) {
20061 a = data_array_init();
20062 buffer_copy_string_buffer(a->key, da_file->key);
20065 ds = data_string_init();
20068 buffer_copy_string(ds->key, "method");
20069 - buffer_copy_string(ds->value, method);
20071 + buffer_copy_string_buffer(ds->value, method);
20073 array_insert_unique(a->value, (data_unset *)ds);
20076 ds = data_string_init();
20079 buffer_copy_string(ds->key, "realm");
20080 - buffer_copy_string(ds->value, realm);
20082 + buffer_copy_string_buffer(ds->value, realm);
20084 array_insert_unique(a->value, (data_unset *)ds);
20087 ds = data_string_init();
20090 buffer_copy_string(ds->key, "require");
20091 - buffer_copy_string(ds->value, require);
20093 + buffer_copy_string_buffer(ds->value, require);
20095 array_insert_unique(a->value, (data_unset *)ds);
20098 array_insert_unique(s->auth_require, (data_unset *)a);
20103 switch(s->auth_backend) {
20104 case AUTH_BACKEND_PLAIN:
20105 if (s->auth_plain_userfile->used) {
20108 if (-1 == (fd = open(s->auth_plain_userfile->ptr, O_RDONLY))) {
20109 - log_error_write(srv, __FILE__, __LINE__, "sbss",
20110 + log_error_write(srv, __FILE__, __LINE__, "sbss",
20111 "opening auth.backend.plain.userfile:", s->auth_plain_userfile,
20112 "failed:", strerror(errno));
20113 return HANDLER_ERROR;
20114 @@ -516,7 +517,7 @@
20117 if (-1 == (fd = open(s->auth_htpasswd_userfile->ptr, O_RDONLY))) {
20118 - log_error_write(srv, __FILE__, __LINE__, "sbss",
20119 + log_error_write(srv, __FILE__, __LINE__, "sbss",
20120 "opening auth.backend.htpasswd.userfile:", s->auth_htpasswd_userfile,
20121 "failed:", strerror(errno));
20122 return HANDLER_ERROR;
20123 @@ -529,7 +530,7 @@
20126 if (-1 == (fd = open(s->auth_htdigest_userfile->ptr, O_RDONLY))) {
20127 - log_error_write(srv, __FILE__, __LINE__, "sbss",
20128 + log_error_write(srv, __FILE__, __LINE__, "sbss",
20129 "opening auth.backend.htdigest.userfile:", s->auth_htdigest_userfile,
20130 "failed:", strerror(errno));
20131 return HANDLER_ERROR;
20132 @@ -554,75 +555,75 @@
20133 handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s) {
20138 if (s->auth_ldap_basedn->used == 0) {
20139 log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.base-dn has to be set");
20142 return HANDLER_ERROR;
20147 if (s->auth_ldap_filter->used) {
20154 if (NULL == (dollar = strchr(s->auth_ldap_filter->ptr, '$'))) {
20155 log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '$'");
20158 return HANDLER_ERROR;
20162 buffer_copy_string_len(s->ldap_filter_pre, s->auth_ldap_filter->ptr, dollar - s->auth_ldap_filter->ptr);
20163 buffer_copy_string(s->ldap_filter_post, dollar+1);
20167 if (s->auth_ldap_hostname->used) {
20168 if (NULL == (s->ldap = ldap_init(s->auth_ldap_hostname->ptr, LDAP_PORT))) {
20169 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
20172 return HANDLER_ERROR;
20176 ret = LDAP_VERSION3;
20177 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(s->ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
20178 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
20181 return HANDLER_ERROR;
20184 if (s->auth_ldap_starttls) {
20185 - /* if no CA file is given, it is ok, as we will use encryption
20186 + /* if no CA file is given, it is ok, as we will use encryption
20187 * if the server requires a CAfile it will tell us */
20188 if (!buffer_is_empty(s->auth_ldap_cafile)) {
20189 - if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
20190 + if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
20191 s->auth_ldap_cafile->ptr))) {
20192 - log_error_write(srv, __FILE__, __LINE__, "ss",
20193 + log_error_write(srv, __FILE__, __LINE__, "ss",
20194 "Loading CA certificate failed:", ldap_err2string(ret));
20197 return HANDLER_ERROR;
20202 if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(s->ldap, NULL, NULL))) {
20203 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
20206 return HANDLER_ERROR;
20214 if (s->auth_ldap_binddn->used) {
20215 if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, s->auth_ldap_binddn->ptr, s->auth_ldap_bindpw->ptr))) {
20216 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
20219 return HANDLER_ERROR;
20222 if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, NULL, NULL))) {
20223 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
20226 return HANDLER_ERROR;
20229 @@ -641,8 +642,8 @@
20230 p->set_defaults = mod_auth_set_defaults;
20231 p->handle_uri_clean = mod_auth_uri_handler;
20232 p->cleanup = mod_auth_free;
20240 --- ../lighttpd-1.4.11/src/mod_cgi.c 2006-02-22 15:15:10.000000000 +0200
20241 +++ lighttpd-1.5.0/src/mod_cgi.c 2006-09-07 00:57:05.000000000 +0300
20243 #include <sys/types.h>
20245 -#include <winsock2.h>
20247 -#include <sys/socket.h>
20248 -#include <sys/wait.h>
20249 -#include <sys/mman.h>
20251 -#include <netinet/in.h>
20253 -#include <arpa/inet.h>
20256 -#include <unistd.h>
20258 #include <stdlib.h>
20259 #include <string.h>
20260 -#include <fdevent.h>
20261 #include <signal.h>
20263 #include <assert.h>
20266 #include "connections.h"
20267 #include "joblist.h"
20268 -#include "http_chunk.h"
20269 +#include "fdevent.h"
20271 #include "plugin.h"
20272 +#include "http_resp.h"
20274 +#include "sys-files.h"
20275 +#include "sys-mmap.h"
20276 +#include "sys-socket.h"
20277 +#include "sys-strings.h"
20278 +#include "sys-process.h"
20280 #ifdef HAVE_SYS_FILIO_H
20281 # include <sys/filio.h>
20282 @@ -40,11 +34,12 @@
20296 @@ -58,57 +53,68 @@
20299 buffer_pid_t cgi_pid;
20303 - buffer *parse_response;
20308 plugin_config **config_storage;
20310 - plugin_config conf;
20312 + plugin_config conf;
20317 + CGI_STATE_CONNECTING,
20318 + CGI_STATE_READ_RESPONSE_HEADER,
20319 + CGI_STATE_READ_RESPONSE_CONTENT
20325 - int fde_ndx; /* index into the fd-event buffer */
20327 - connection *remote_conn; /* dumb pointer */
20328 - plugin_data *plugin_data; /* dumb pointer */
20330 - buffer *response;
20331 - buffer *response_header;
20334 -static handler_ctx * cgi_handler_ctx_init() {
20335 - handler_ctx *hctx = calloc(1, sizeof(*hctx));
20340 - hctx->response = buffer_init();
20341 - hctx->response_header = buffer_init();
20348 -static void cgi_handler_ctx_free(handler_ctx *hctx) {
20349 - buffer_free(hctx->response);
20350 - buffer_free(hctx->response_header);
20353 + cgi_state_t state;
20355 + connection *remote_con; /* dumb pointer */
20358 +static cgi_session * cgi_session_init() {
20359 + cgi_session *sess = calloc(1, sizeof(*sess));
20362 + sess->sock = iosocket_init();
20363 + sess->wb = chunkqueue_init();
20364 + sess->rb = chunkqueue_init();
20369 -enum {FDEVENT_HANDLED_UNSET, FDEVENT_HANDLED_FINISHED, FDEVENT_HANDLED_NOT_FINISHED, FDEVENT_HANDLED_ERROR};
20370 +static void cgi_session_free(cgi_session *sess) {
20371 + if (!sess) return;
20373 + iosocket_free(sess->sock);
20375 + chunkqueue_free(sess->wb);
20376 + chunkqueue_free(sess->rb);
20381 INIT_FUNC(mod_cgi_init) {
20385 p = calloc(1, sizeof(*p));
20390 p->tmp_buf = buffer_init();
20391 - p->parse_response = buffer_init();
20393 + p->resp = http_response_init();
20398 @@ -116,62 +122,62 @@
20399 FREE_FUNC(mod_cgi_free) {
20400 plugin_data *p = p_d;
20401 buffer_pid_t *r = &(p->cgi_pid);
20407 if (p->config_storage) {
20409 for (i = 0; i < srv->config_context->used; i++) {
20410 plugin_config *s = p->config_storage[i];
20413 array_free(s->cgi);
20418 free(p->config_storage);
20423 if (r->ptr) free(r->ptr);
20426 buffer_free(p->tmp_buf);
20427 - buffer_free(p->parse_response);
20429 + http_response_free(p->resp);
20434 return HANDLER_GO_ON;
20437 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
20438 plugin_data *p = p_d;
20441 - config_values_t cv[] = {
20443 + config_values_t cv[] = {
20444 { "cgi.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
20445 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET}
20448 if (!p) return HANDLER_ERROR;
20451 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
20454 for (i = 0; i < srv->config_context->used; i++) {
20458 s = calloc(1, sizeof(plugin_config));
20462 s->cgi = array_init();
20465 cv[0].destination = s->cgi;
20468 p->config_storage[i] = s;
20471 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
20472 return HANDLER_ERROR;
20477 return HANDLER_GO_ON;
20480 @@ -180,13 +186,13 @@
20483 buffer_pid_t *r = &(p->cgi_pid);
20488 for (i = 0; i < r->used; i++) {
20489 if (r->ptr[i] > m) m = r->ptr[i];
20493 if (r->size == 0) {
20495 r->ptr = malloc(sizeof(*r->ptr) * r->size);
20496 @@ -194,321 +200,179 @@
20498 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
20502 r->ptr[r->used++] = pid;
20508 static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) {
20510 buffer_pid_t *r = &(p->cgi_pid);
20515 for (i = 0; i < r->used; i++) {
20516 if (r->ptr[i] == pid) break;
20520 if (i != r->used) {
20524 if (i != r->used - 1) {
20525 r->ptr[i] = r->ptr[r->used - 1];
20534 -static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
20541 - buffer_copy_string_buffer(p->parse_response, in);
20543 - for (s = p->parse_response->ptr;
20544 - NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n')));
20545 - s = ns + (eol == EOL_RN ? 2 : 1), line++) {
20546 - const char *key, *value;
20553 - 0 == strncmp(s, "HTTP/1.", 7)) {
20554 - /* non-parsed header ... we parse them anyway */
20556 - if ((s[7] == '1' ||
20560 - /* after the space should be a status code for us */
20562 - status = strtol(s+9, NULL, 10);
20564 - if (con->http_status >= 100 &&
20565 - con->http_status < 1000) {
20566 - /* we expected 3 digits and didn't got them */
20567 - con->parsed_response |= HTTP_STATUS;
20568 - con->http_status = status;
20574 - if (NULL == (value = strchr(s, ':'))) {
20575 - /* we expect: "<key>: <value>\r\n" */
20579 - key_len = value - key;
20583 - while (*value == ' ' || *value == '\t') value++;
20585 - if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
20586 - ds = data_response_init();
20588 - buffer_copy_string_len(ds->key, key, key_len);
20589 - buffer_copy_string(ds->value, value);
20591 - array_insert_unique(con->response.headers, (data_unset *)ds);
20593 - switch(key_len) {
20595 - if (0 == strncasecmp(key, "Date", key_len)) {
20596 - con->parsed_response |= HTTP_DATE;
20600 - if (0 == strncasecmp(key, "Status", key_len)) {
20601 - con->http_status = strtol(value, NULL, 10);
20602 - con->parsed_response |= HTTP_STATUS;
20606 - if (0 == strncasecmp(key, "Location", key_len)) {
20607 - con->parsed_response |= HTTP_LOCATION;
20611 - if (0 == strncasecmp(key, "Connection", key_len)) {
20612 - con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
20613 - con->parsed_response |= HTTP_CONNECTION;
20617 - if (0 == strncasecmp(key, "Content-Length", key_len)) {
20618 - con->response.content_length = strtol(value, NULL, 10);
20619 - con->parsed_response |= HTTP_CONTENT_LENGTH;
20628 - /* CGI/1.1 rev 03 - 7.2.1.2 */
20629 - if ((con->parsed_response & HTTP_LOCATION) &&
20630 - !(con->parsed_response & HTTP_STATUS)) {
20631 - con->http_status = 302;
20632 +static int cgi_demux_response(server *srv, connection *con, plugin_data *p) {
20633 + cgi_session *sess = con->plugin_ctx[p->id];
20636 + switch(srv->network_backend_read(srv, con, sess->sock, sess->rb)) {
20637 + case NETWORK_STATUS_SUCCESS:
20638 + /* we got content */
20640 + case NETWORK_STATUS_WAIT_FOR_EVENT:
20642 + case NETWORK_STATUS_CONNECTION_CLOSE:
20643 + /* this is a bit too early */
20644 + ERROR("%s", "cgi-connection got closed before we read the response-header (CGI died ?)");
20648 + ERROR("%s", "oops, read-pipe-read failed and I don't know why");
20655 + /* looks like we got some content
20657 + * split off the header from the incoming stream
20660 -static int cgi_demux_response(server *srv, handler_ctx *hctx) {
20661 - plugin_data *p = hctx->plugin_data;
20662 - connection *con = hctx->remote_conn;
20667 - buffer_prepare_copy(hctx->response, 1024);
20668 - if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
20669 - if (errno == EAGAIN || errno == EINTR) {
20670 - /* would block, wait for signal */
20671 - return FDEVENT_HANDLED_NOT_FINISHED;
20674 - log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
20675 - return FDEVENT_HANDLED_ERROR;
20679 - /* read finished */
20681 - con->file_finished = 1;
20683 - /* send final chunk */
20684 - http_chunk_append_mem(srv, con, NULL, 0);
20685 - joblist_append(srv, con);
20687 - return FDEVENT_HANDLED_FINISHED;
20690 - hctx->response->ptr[n] = '\0';
20691 - hctx->response->used = n+1;
20693 - /* split header from body */
20695 - if (con->file_started == 0) {
20697 - int in_header = 0;
20698 - int header_end = 0;
20699 - int cp, eol = EOL_UNSET;
20702 - buffer_append_string_buffer(hctx->response_header, hctx->response);
20704 - /* nph (non-parsed headers) */
20705 - if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
20707 - /* search for the \r\n\r\n or \n\n in the string */
20708 - for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
20709 - if (*c == ':') in_header = 1;
20710 - else if (*c == '\n') {
20711 - if (in_header == 0) {
20712 - /* got a response without a response header */
20719 - if (eol == EOL_UNSET) eol = EOL_N;
20721 - if (*(c+1) == '\n') {
20726 - } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
20727 - if (in_header == 0) {
20728 - /* got a response without a response header */
20735 - if (eol == EOL_UNSET) eol = EOL_RN;
20738 - *(c+2) == '\r' &&
20739 - *(c+3) == '\n') {
20744 - /* skip the \n */
20748 + if (con->file_started == 0) {
20750 + int have_content_length = 0;
20752 + http_response_reset(p->resp);
20754 + /* the response header is not fully received yet,
20756 + * extract the http-response header from the rb-cq
20758 + switch (http_response_parse_cq(sess->rb, p->resp)) {
20759 + case PARSE_ERROR:
20760 + /* parsing failed */
20762 + TRACE("%s", "response parser failed");
20764 + con->http_status = 502; /* Bad Gateway */
20766 + case PARSE_NEED_MORE:
20768 + case PARSE_SUCCESS:
20769 + con->http_status = p->resp->status;
20771 + chunkqueue_remove_finished_chunks(sess->rb);
20773 + /* copy the http-headers */
20774 + for (i = 0; i < p->resp->headers->used; i++) {
20775 + const char *ign[] = { "Status", "Connection", NULL };
20779 + data_string *header = (data_string *)p->resp->headers->data[i];
20781 + /* some headers are ignored by default */
20782 + for (j = 0; ign[j]; j++) {
20783 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
20787 - if (header_end) {
20789 - /* no header, but a body */
20791 - if (con->request.http_version == HTTP_VERSION_1_1) {
20792 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
20795 - http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
20796 - joblist_append(srv, con);
20798 - size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
20799 - size_t blen = hctx->response_header->used - hlen - 1;
20801 - /* a small hack: terminate after at the second \r */
20802 - hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
20803 - hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
20805 - /* parse the response header */
20806 - cgi_response_parse(srv, con, p, hctx->response_header, eol);
20808 - /* enable chunked-transfer-encoding */
20809 - if (con->request.http_version == HTTP_VERSION_1_1 &&
20810 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
20811 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
20814 - if ((hctx->response->used != hlen) && blen > 0) {
20815 - http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
20816 - joblist_append(srv, con);
20818 + if (ign[j]) continue;
20820 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
20821 + /* CGI/1.1 rev 03 - 7.2.1.2 */
20822 + if (con->http_status == 0) con->http_status = 302;
20823 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
20824 + have_content_length = 1;
20827 - con->file_started = 1;
20828 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
20829 + ds = data_response_init();
20831 + buffer_copy_string_buffer(ds->key, header->key);
20832 + buffer_copy_string_buffer(ds->value, header->value);
20834 + array_insert_unique(con->response.headers, (data_unset *)ds);
20837 - http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
20838 - joblist_append(srv, con);
20840 + con->file_started = 1;
20841 + sess->state = CGI_STATE_READ_RESPONSE_CONTENT;
20843 + if (con->request.http_version == HTTP_VERSION_1_1 &&
20844 + !have_content_length) {
20845 + con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
20852 - log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
20856 - return FDEVENT_HANDLED_NOT_FINISHED;
20858 + /* FIXME: pass the response-header to the other plugins to
20859 + * setup the filter-queue
20861 + * - use next-queue instead of con->write_queue
20864 + /* copy the content to the next cq */
20865 + for (c = sess->rb->first; c; c = c->next) {
20866 + chunkqueue_append_mem(con->send, c->mem->ptr + c->offset, c->mem->used - c->offset);
20868 + c->offset = c->mem->used - 1;
20871 + chunkqueue_remove_finished_chunks(sess->rb);
20872 + joblist_append(srv, con);
20877 -static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) {
20878 +static handler_t cgi_connection_close(server *srv, connection *con, plugin_data *p) {
20879 + cgi_session *sess = con->plugin_ctx[p->id];
20885 - if (NULL == hctx) return HANDLER_GO_ON;
20887 - p = hctx->plugin_data;
20888 - con = hctx->remote_conn;
20891 + if (NULL == sess) return HANDLER_GO_ON;
20892 if (con->mode != p->id) return HANDLER_GO_ON;
20898 /* the connection to the browser went away, but we still have a connection
20899 - * to the CGI script
20900 + * to the CGI script
20902 * close cgi-connection
20905 - if (hctx->fd != -1) {
20907 + if (sess->sock->fd != -1) {
20908 /* close connection to the cgi-script */
20909 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
20910 - fdevent_unregister(srv->ev, hctx->fd);
20912 - if (close(hctx->fd)) {
20913 - log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
20917 - hctx->fde_ndx = -1;
20918 + fdevent_event_del(srv->ev, sess->sock);
20919 + fdevent_unregister(srv->ev, sess->sock);
20927 con->plugin_ctx[p->id] = NULL;
20930 /* is this a good idea ? */
20931 - cgi_handler_ctx_free(hctx);
20933 + cgi_session_free(sess);
20936 /* if waitpid hasn't been called by response.c yet, do it here */
20938 /* check if the CGI-script is already gone */
20940 switch(waitpid(pid, &status, WNOHANG)) {
20942 /* not finished yet */
20943 @@ -519,35 +383,34 @@
20946 if (errno == EINTR) break;
20949 - * errno == ECHILD happens if _subrequest catches the process-status before
20952 + * errno == ECHILD happens if _subrequest catches the process-status before
20953 * we have read the response of the cgi process
20957 * -> WAIT_FOR_EVENT
20959 * -> we get here with waitpid == ECHILD
20963 if (errno == ECHILD) return HANDLER_GO_ON;
20966 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
20967 return HANDLER_ERROR;
20969 /* Send an error if we haven't sent any data yet */
20970 if (0 == con->file_started) {
20971 - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
20972 - con->http_status = 500;
20973 + if (con->http_status == 0) con->http_status = 500;
20974 con->mode = DIRECT;
20978 if (WIFEXITED(status)) {
20980 log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", pid);
20985 return HANDLER_GO_ON;
20987 log_error_write(srv, __FILE__, __LINE__, "sd", "cgi died, pid:", pid);
20988 @@ -555,122 +418,126 @@
20989 return HANDLER_GO_ON;
20996 kill(pid, SIGTERM);
20999 /* cgi-script is still alive, queue the PID for removal */
21000 cgi_pid_add(srv, p, pid);
21004 return HANDLER_GO_ON;
21007 static handler_t cgi_connection_close_callback(server *srv, connection *con, void *p_d) {
21008 plugin_data *p = p_d;
21010 - return cgi_connection_close(srv, con->plugin_ctx[p->id]);
21012 + return cgi_connection_close(srv, con, p);
21016 static handler_t cgi_handle_fdevent(void *s, void *ctx, int revents) {
21017 server *srv = (server *)s;
21018 - handler_ctx *hctx = ctx;
21019 - connection *con = hctx->remote_conn;
21021 - joblist_append(srv, con);
21023 - if (hctx->fd == -1) {
21024 - log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "invalid cgi-fd");
21026 - return HANDLER_ERROR;
21029 + cgi_session *sess = ctx;
21030 + connection *con = sess->remote_con;
21033 if (revents & FDEVENT_IN) {
21034 - switch (cgi_demux_response(srv, hctx)) {
21035 - case FDEVENT_HANDLED_NOT_FINISHED:
21036 + switch (sess->state) {
21037 + case CGI_STATE_READ_RESPONSE_HEADER:
21038 + /* parse the header and set file-started, the demuxer will care about it */
21039 + joblist_append(srv, con);
21042 - case FDEVENT_HANDLED_FINISHED:
21043 - /* we are done */
21045 + case CGI_STATE_READ_RESPONSE_CONTENT:
21046 + /* just forward the content to the out-going queue */
21048 + chunkqueue_remove_finished_chunks(sess->rb);
21050 + switch (srv->network_backend_read(srv, sess->remote_con, sess->sock, sess->rb)) {
21051 + case NETWORK_STATUS_CONNECTION_CLOSE:
21052 + fdevent_event_del(srv->ev, sess->sock);
21054 + /* the connection is gone
21055 + * make the connect */
21056 + sess->remote_con->send->is_closed = 1;
21058 - log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "finished");
21059 + fdevent_event_del(srv->ev, sess->sock);
21061 - cgi_connection_close(srv, hctx);
21063 - /* if we get a IN|HUP and have read everything don't exec the close twice */
21064 - return HANDLER_FINISHED;
21065 - case FDEVENT_HANDLED_ERROR:
21066 - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
21067 - con->http_status = 500;
21068 - con->mode = DIRECT;
21070 - log_error_write(srv, __FILE__, __LINE__, "s", "demuxer failed: ");
21071 + case NETWORK_STATUS_SUCCESS:
21072 + /* read even more, do we have all the content */
21074 + /* how much do we want to read ? */
21076 + /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
21078 + chunkqueue_remove_finished_chunks(sess->rb);
21080 + /* copy the content to the next cq */
21081 + for (c = sess->rb->first; c; c = c->next) {
21082 + if (c->mem->used == 0) continue;
21084 + http_chunk_append_mem(srv, sess->remote_con, c->mem->ptr + c->offset, c->mem->used - c->offset);
21086 + c->offset = c->mem->used - 1;
21089 + chunkqueue_remove_finished_chunks(sess->rb);
21091 + if (sess->remote_con->send->is_closed) {
21092 + /* send final HTTP-Chunk packet */
21093 + http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
21098 + ERROR("%s", "oops, we failed to read");
21102 + joblist_append(srv, sess->remote_con);
21105 + TRACE("unexpected state for a FDEVENT_IN: %d", sess->state);
21111 if (revents & FDEVENT_OUT) {
21112 /* nothing to do */
21116 /* perhaps this issue is already handled */
21117 if (revents & FDEVENT_HUP) {
21118 - /* check if we still have a unfinished header package which is a body in reality */
21119 - if (con->file_started == 0 &&
21120 - hctx->response_header->used) {
21121 - con->file_started = 1;
21122 - http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
21123 - joblist_append(srv, con);
21126 - if (con->file_finished == 0) {
21127 - http_chunk_append_mem(srv, con, NULL, 0);
21128 - joblist_append(srv, con);
21131 - con->file_finished = 1;
21133 - if (chunkqueue_is_empty(con->write_queue)) {
21134 - /* there is nothing left to write */
21135 - connection_set_state(srv, con, CON_STATE_RESPONSE_END);
21137 - /* used the write-handler to finish the request on demand */
21142 - log_error_write(srv, __FILE__, __LINE__, "sddd", "got HUP from cgi", con->fd, hctx->fd, revents);
21145 - /* rtsigs didn't liked the close */
21146 - cgi_connection_close(srv, hctx);
21147 + con->send->is_closed = 1;
21149 + fdevent_event_del(srv->ev, sess->sock);
21151 + /* someone has to close this socket now :) */
21152 + http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
21153 + joblist_append(srv, sess->remote_con);
21154 } else if (revents & FDEVENT_ERR) {
21155 - con->file_finished = 1;
21157 + con->send->is_closed = 1;
21159 /* kill all connections to the cgi process */
21160 - cgi_connection_close(srv, hctx);
21162 - log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR");
21164 - return HANDLER_ERROR;
21165 + fdevent_event_del(srv->ev, sess->sock);
21169 return HANDLER_FINISHED;
21173 static int cgi_env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
21177 if (!key || !val) return -1;
21180 dst = malloc(key_len + val_len + 3);
21181 memcpy(dst, key, key_len);
21182 dst[key_len] = '=';
21183 /* add the \0 from the value */
21184 memcpy(dst + key_len + 1, val, val_len + 1);
21187 if (env->size == 0) {
21189 env->ptr = malloc(env->size * sizeof(*env->ptr));
21190 @@ -678,45 +545,45 @@
21192 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
21196 env->ptr[env->used++] = dst;
21202 static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *cgi_handler) {
21207 char b2[INET6_ADDRSTRLEN + 1];
21212 int from_cgi_fds[2];
21220 if (cgi_handler->used > 1) {
21221 /* stat the exec file */
21222 if (-1 == (stat(cgi_handler->ptr, &st))) {
21223 - log_error_write(srv, __FILE__, __LINE__, "sbss",
21224 + log_error_write(srv, __FILE__, __LINE__, "sbss",
21225 "stat for cgi-handler", cgi_handler,
21226 "failed:", strerror(errno));
21232 if (pipe(to_cgi_fds)) {
21233 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
21238 if (pipe(from_cgi_fds)) {
21239 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
21245 switch (pid = fork()) {
21247 @@ -730,44 +597,40 @@
21250 server_socket *srv_sock = con->srv_socket;
21253 /* move stdout to from_cgi_fd[1] */
21254 close(STDOUT_FILENO);
21255 dup2(from_cgi_fds[1], STDOUT_FILENO);
21256 close(from_cgi_fds[1]);
21258 close(from_cgi_fds[0]);
21261 /* move the stdin to to_cgi_fd[0] */
21262 close(STDIN_FILENO);
21263 dup2(to_cgi_fds[0], STDIN_FILENO);
21264 close(to_cgi_fds[0]);
21266 close(to_cgi_fds[1]);
21269 - * this is not nice, but it works
21271 - * we feed the stderr of the CGI to our errorlog, if possible
21274 + * FIXME: add a event-handler for STDERR_FILENO and let it LOG()
21276 - if (srv->errorlog_mode == ERRORLOG_FILE) {
21277 - close(STDERR_FILENO);
21278 - dup2(srv->errorlog_fd, STDERR_FILENO);
21282 + close(STDERR_FILENO);
21284 /* create environment */
21290 cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
21292 if (!buffer_is_empty(con->server_name)) {
21293 cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
21296 - s = inet_ntop(srv_sock->addr.plain.sa_family,
21297 - srv_sock->addr.plain.sa_family == AF_INET6 ?
21298 + s = inet_ntop(srv_sock->addr.plain.sa_family,
21299 + srv_sock->addr.plain.sa_family == AF_INET6 ?
21300 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
21301 (const void *) &(srv_sock->addr.ipv4.sin_addr),
21303 @@ -779,10 +642,10 @@
21304 cgi_env_add(&env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
21306 s = get_http_version_name(con->request.http_version);
21309 cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
21315 ntohs(srv_sock->addr.plain.sa_family == AF_INET6 ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
21317 @@ -790,10 +653,10 @@
21320 cgi_env_add(&env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
21324 - s = inet_ntop(srv_sock->addr.plain.sa_family,
21325 - srv_sock->addr.plain.sa_family == AF_INET6 ?
21326 + s = inet_ntop(srv_sock->addr.plain.sa_family,
21327 + srv_sock->addr.plain.sa_family == AF_INET6 ?
21328 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
21329 (const void *) &(srv_sock->addr.ipv4.sin_addr),
21331 @@ -811,15 +674,18 @@
21332 cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
21333 if (!buffer_is_empty(con->uri.query)) {
21334 cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
21336 + /* set a empty QUERY_STRING */
21337 + cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
21339 if (!buffer_is_empty(con->request.orig_uri)) {
21340 cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
21347 - s = inet_ntop(con->dst_addr.plain.sa_family,
21348 - con->dst_addr.plain.sa_family == AF_INET6 ?
21349 + s = inet_ntop(con->dst_addr.plain.sa_family,
21350 + con->dst_addr.plain.sa_family == AF_INET6 ?
21351 (const void *) &(con->dst_addr.ipv6.sin6_addr) :
21352 (const void *) &(con->dst_addr.ipv4.sin_addr),
21354 @@ -828,7 +694,7 @@
21356 cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
21361 ntohs(con->dst_addr.plain.sa_family == AF_INET6 ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
21363 @@ -836,19 +702,19 @@
21366 cgi_env_add(&env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
21369 if (!buffer_is_empty(con->authed_user)) {
21370 cgi_env_add(&env, CONST_STR_LEN("REMOTE_USER"),
21371 CONST_BUF_LEN(con->authed_user));
21375 /* request.content_length < SSIZE_MAX, see request.c */
21376 ltostr(buf, con->request.content_length);
21377 cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
21378 cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
21379 cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
21380 cgi_env_add(&env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
21384 if (NULL != (s = getenv("LD_PRELOAD"))) {
21385 cgi_env_add(&env, CONST_STR_LEN("LD_PRELOAD"), s, strlen(s));
21386 @@ -863,24 +729,24 @@
21387 cgi_env_add(&env, CONST_STR_LEN("SYSTEMROOT"), s, strlen(s));
21392 for (n = 0; n < con->request.headers->used; n++) {
21396 ds = (data_string *)con->request.headers->data[n];
21399 if (ds->value->used && ds->key->used) {
21403 buffer_reset(p->tmp_buf);
21406 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
21407 buffer_copy_string(p->tmp_buf, "HTTP_");
21408 p->tmp_buf->used--; /* strip \0 after HTTP_ */
21412 buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
21415 for (j = 0; j < ds->key->used - 1; j++) {
21417 if (light_isalpha(ds->key->ptr[j])) {
21418 @@ -893,46 +759,46 @@
21419 p->tmp_buf->ptr[p->tmp_buf->used++] = cr;
21421 p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
21424 cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
21429 for (n = 0; n < con->environment->used; n++) {
21433 ds = (data_string *)con->environment->data[n];
21436 if (ds->value->used && ds->key->used) {
21440 buffer_reset(p->tmp_buf);
21443 buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
21446 for (j = 0; j < ds->key->used - 1; j++) {
21447 - p->tmp_buf->ptr[p->tmp_buf->used++] =
21448 - isalpha((unsigned char)ds->key->ptr[j]) ?
21449 + p->tmp_buf->ptr[p->tmp_buf->used++] =
21450 + isalpha((unsigned char)ds->key->ptr[j]) ?
21451 toupper((unsigned char)ds->key->ptr[j]) : '_';
21453 p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
21456 cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
21461 if (env.size == env.used) {
21463 env.ptr = realloc(env.ptr, env.size * sizeof(*env.ptr));
21467 env.ptr[env.used] = NULL;
21472 args = malloc(sizeof(*args) * argc);
21476 if (cgi_handler->used > 1) {
21477 args[i++] = cgi_handler->ptr;
21479 @@ -942,7 +808,7 @@
21480 /* search for the last / */
21481 if (NULL != (c = strrchr(con->physical.path->ptr, '/'))) {
21485 /* change to the physical directory */
21486 if (-1 == chdir(con->physical.path->ptr)) {
21487 log_error_write(srv, __FILE__, __LINE__, "ssb", "chdir failed:", strerror(errno), con->physical.path);
21488 @@ -952,14 +818,14 @@
21490 /* we don't need the client socket */
21491 for (i = 3; i < 256; i++) {
21492 - if (i != srv->errorlog_fd) close(i);
21498 execve(args[0], args, env.ptr);
21501 log_error_write(srv, __FILE__, __LINE__, "sss", "CGI failed:", strerror(errno), args[0]);
21507 @@ -969,16 +835,16 @@
21508 log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno));
21511 - handler_ctx *hctx;
21512 + cgi_session *sess;
21515 close(from_cgi_fds[1]);
21516 close(to_cgi_fds[0]);
21519 if (con->request.content_length) {
21520 - chunkqueue *cq = con->request_content_queue;
21521 + chunkqueue *cq = con->recv;
21525 assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
21527 /* there is content to send */
21528 @@ -993,16 +859,16 @@
21529 if (-1 == c->file.fd && /* open the file if not already open */
21530 -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
21531 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
21534 close(from_cgi_fds[0]);
21535 close(to_cgi_fds[1]);
21539 c->file.mmap.length = c->file.length;
21542 if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.mmap.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
21543 - log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
21544 + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
21545 strerror(errno), c->file.name, c->file.fd);
21547 close(from_cgi_fds[0]);
21548 @@ -1012,7 +878,7 @@
21554 /* chunk_reset() or chunk_free() will cleanup for us */
21557 @@ -1020,7 +886,7 @@
21560 con->http_status = 507;
21565 con->http_status = 403;
21566 @@ -1033,7 +899,7 @@
21569 con->http_status = 507;
21574 con->http_status = 403;
21575 @@ -1056,103 +922,95 @@
21578 close(to_cgi_fds[1]);
21581 /* register PID and wait for them asyncronously */
21583 buffer_reset(con->physical.path);
21585 - hctx = cgi_handler_ctx_init();
21587 - hctx->remote_conn = con;
21588 - hctx->plugin_data = p;
21590 - hctx->fd = from_cgi_fds[0];
21591 - hctx->fde_ndx = -1;
21593 - con->plugin_ctx[p->id] = hctx;
21595 - fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx);
21596 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
21598 - if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
21600 + sess = cgi_session_init();
21602 + sess->remote_con = con;
21605 + assert(sess->sock);
21607 + sess->sock->fd = from_cgi_fds[0];
21608 + sess->sock->type = IOSOCKET_TYPE_PIPE;
21610 + if (-1 == fdevent_fcntl_set(srv->ev, sess->sock)) {
21611 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
21613 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
21614 - fdevent_unregister(srv->ev, hctx->fd);
21616 - log_error_write(srv, __FILE__, __LINE__, "sd", "cgi close:", hctx->fd);
21620 - cgi_handler_ctx_free(hctx);
21622 - con->plugin_ctx[p->id] = NULL;
21625 + cgi_session_free(sess);
21631 + con->plugin_ctx[p->id] = sess;
21633 + fdevent_register(srv->ev, sess->sock, cgi_handle_fdevent, sess);
21634 + fdevent_event_add(srv->ev, sess->sock, FDEVENT_IN);
21636 + sess->state = CGI_STATE_READ_RESPONSE_HEADER;
21649 -#define PATCH(x) \
21650 - p->conf.x = s->x;
21651 static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p) {
21653 plugin_config *s = p->config_storage[0];
21658 + PATCH_OPTION(cgi);
21660 /* skip the first, the global context */
21661 for (i = 1; i < srv->config_context->used; i++) {
21662 data_config *dc = (data_config *)srv->config_context->data[i];
21663 s = p->config_storage[i];
21666 /* condition didn't match */
21667 if (!config_check_cond(srv, con, dc)) continue;
21671 for (j = 0; j < dc->value->used; j++) {
21672 data_unset *du = dc->value->data[j];
21675 if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.assign"))) {
21677 + PATCH_OPTION(cgi);
21687 URIHANDLER_FUNC(cgi_is_handled) {
21689 plugin_data *p = p_d;
21690 buffer *fn = con->physical.path;
21693 if (fn->used == 0) return HANDLER_GO_ON;
21696 mod_cgi_patch_connection(srv, con, p);
21699 s_len = fn->used - 1;
21702 for (k = 0; k < p->conf.cgi->used; k++) {
21703 data_string *ds = (data_string *)p->conf.cgi->data[k];
21704 size_t ct_len = ds->key->used - 1;
21707 if (ds->key->used == 0) continue;
21708 if (s_len < ct_len) continue;
21711 if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
21712 if (cgi_create_env(srv, con, p, ds->value)) {
21713 con->http_status = 500;
21716 buffer_reset(con->physical.path);
21717 return HANDLER_FINISHED;
21719 @@ -1160,7 +1018,7 @@
21725 return HANDLER_GO_ON;
21728 @@ -1168,11 +1026,11 @@
21729 plugin_data *p = p_d;
21731 /* the trigger handle only cares about lonely PID which we have to wait for */
21735 for (ndx = 0; ndx < p->cgi_pid.used; ndx++) {
21739 switch(waitpid(p->cgi_pid.ptr[ndx], &status, WNOHANG)) {
21741 /* not finished yet */
21742 @@ -1182,7 +1040,7 @@
21745 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
21748 return HANDLER_ERROR;
21751 @@ -1193,96 +1051,104 @@
21753 log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
21757 cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]);
21758 - /* del modified the buffer structure
21759 + /* del modified the buffer structure
21760 * and copies the last entry to the current one
21761 * -> recheck the current index
21768 return HANDLER_GO_ON;
21771 SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {
21773 plugin_data *p = p_d;
21774 - handler_ctx *hctx = con->plugin_ctx[p->id];
21776 + cgi_session *sess = con->plugin_ctx[p->id];
21778 if (con->mode != p->id) return HANDLER_GO_ON;
21779 - if (NULL == hctx) return HANDLER_GO_ON;
21781 + if (NULL == sess) return HANDLER_GO_ON;
21783 + switch (cgi_demux_response(srv, con, p)) {
21787 + cgi_connection_close(srv, con, p);
21789 + /* if we get a IN|HUP and have read everything don't exec the close twice */
21790 + return HANDLER_FINISHED;
21792 + cgi_connection_close(srv, con, p);
21794 + if (0 == con->http_status) con->http_status = 500;
21795 + con->mode = DIRECT;
21797 + return HANDLER_FINISHED;
21801 - log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", hctx, hctx->pid);
21803 - if (hctx->pid == 0) return HANDLER_FINISHED;
21805 - switch(waitpid(hctx->pid, &status, WNOHANG)) {
21806 + log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", sess, sess->pid);
21808 + if (sess->pid == 0) return HANDLER_FINISHED;
21810 + switch(waitpid(sess->pid, &status, WNOHANG)) {
21812 /* we only have for events here if we don't have the header yet,
21813 * otherwise the event-handler will send us the incoming data */
21814 - if (con->file_started) return HANDLER_FINISHED;
21816 - return HANDLER_WAIT_FOR_EVENT;
21817 + if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
21818 + if (con->send->is_closed) return HANDLER_FINISHED;
21820 + return HANDLER_GO_ON;
21822 if (errno == EINTR) return HANDLER_WAIT_FOR_EVENT;
21825 if (errno == ECHILD && con->file_started == 0) {
21827 - * second round but still not response
21828 + * second round but still not response
21830 - return HANDLER_WAIT_FOR_EVENT;
21831 + return HANDLER_WAIT_FOR_EVENT;
21835 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
21836 con->mode = DIRECT;
21837 con->http_status = 500;
21841 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
21842 - fdevent_unregister(srv->ev, hctx->fd);
21844 - if (close(hctx->fd)) {
21845 - log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
21848 - cgi_handler_ctx_free(hctx);
21853 + fdevent_event_del(srv->ev, sess->sock);
21854 + fdevent_unregister(srv->ev, sess->sock);
21856 + cgi_session_free(sess);
21859 con->plugin_ctx[p->id] = NULL;
21862 return HANDLER_FINISHED;
21864 - /* cgi process exited cleanly
21866 - * check if we already got the response
21869 - if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
21871 + con->send->is_closed = 1;
21873 if (WIFEXITED(status)) {
21876 log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
21879 con->mode = DIRECT;
21880 con->http_status = 500;
21887 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
21888 - fdevent_unregister(srv->ev, hctx->fd);
21890 - if (close(hctx->fd)) {
21891 - log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
21894 - cgi_handler_ctx_free(hctx);
21899 + fdevent_event_del(srv->ev, sess->sock);
21900 + fdevent_unregister(srv->ev, sess->sock);
21902 + cgi_session_free(sess);
21905 con->plugin_ctx[p->id] = NULL;
21906 return HANDLER_FINISHED;
21908 @@ -1297,17 +1163,15 @@
21909 p->name = buffer_init_string("cgi");
21911 p->connection_reset = cgi_connection_close_callback;
21912 - p->handle_subrequest_start = cgi_is_handled;
21913 - p->handle_subrequest = mod_cgi_handle_subrequest;
21915 - p->handle_fdevent = cgi_handle_fdevent;
21917 + p->handle_start_backend = cgi_is_handled;
21918 + p->handle_send_request_content = mod_cgi_handle_subrequest;
21920 p->handle_trigger = cgi_trigger;
21921 p->init = mod_cgi_init;
21922 p->cleanup = mod_cgi_free;
21923 p->set_defaults = mod_fastcgi_set_defaults;
21931 --- ../lighttpd-1.4.11/src/mod_cml.c 2006-01-30 13:51:48.000000000 +0200
21932 +++ lighttpd-1.5.0/src/mod_cml.c 2006-09-07 00:57:05.000000000 +0300
21934 #include <stdlib.h>
21935 #include <string.h>
21937 -#include <unistd.h>
21940 #include "buffer.h"
21941 @@ -20,50 +19,50 @@
21942 /* init the plugin data */
21943 INIT_FUNC(mod_cml_init) {
21947 p = calloc(1, sizeof(*p));
21950 p->basedir = buffer_init();
21951 p->baseurl = buffer_init();
21952 p->trigger_handler = buffer_init();
21958 /* detroy the plugin data */
21959 FREE_FUNC(mod_cml_free) {
21960 plugin_data *p = p_d;
21965 if (!p) return HANDLER_GO_ON;
21968 if (p->config_storage) {
21970 for (i = 0; i < srv->config_context->used; i++) {
21971 plugin_config *s = p->config_storage[i];
21974 buffer_free(s->ext);
21977 buffer_free(s->mc_namespace);
21978 buffer_free(s->power_magnet);
21979 array_free(s->mc_hosts);
21982 #if defined(HAVE_MEMCACHE_H)
21983 if (s->mc) mc_free(s->mc);
21989 free(p->config_storage);
21993 buffer_free(p->trigger_handler);
21994 buffer_free(p->basedir);
21995 buffer_free(p->baseurl);
22001 return HANDLER_GO_ON;
22004 @@ -72,22 +71,22 @@
22005 SETDEFAULTS_FUNC(mod_cml_set_defaults) {
22006 plugin_data *p = p_d;
22009 - config_values_t cv[] = {
22011 + config_values_t cv[] = {
22012 { "cml.extension", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
22013 { "cml.memcache-hosts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
22014 { "cml.memcache-namespace", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
22015 { "cml.power-magnet", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
22016 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
22020 if (!p) return HANDLER_ERROR;
22023 p->config_storage = malloc(srv->config_context->used * sizeof(specific_config *));
22026 for (i = 0; i < srv->config_context->used; i++) {
22030 s = malloc(sizeof(plugin_config));
22031 s->ext = buffer_init();
22032 s->mc_hosts = array_init();
22033 @@ -96,87 +95,84 @@
22034 #if defined(HAVE_MEMCACHE_H)
22039 cv[0].destination = s->ext;
22040 cv[1].destination = s->mc_hosts;
22041 cv[2].destination = s->mc_namespace;
22042 cv[3].destination = s->power_magnet;
22045 p->config_storage[i] = s;
22048 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
22049 return HANDLER_ERROR;
22053 if (s->mc_hosts->used) {
22054 #if defined(HAVE_MEMCACHE_H)
22059 for (k = 0; k < s->mc_hosts->used; k++) {
22060 data_string *ds = (data_string *)s->mc_hosts->data[k];
22063 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
22064 - log_error_write(srv, __FILE__, __LINE__, "sb",
22065 - "connection to host failed:",
22066 + log_error_write(srv, __FILE__, __LINE__, "sb",
22067 + "connection to host failed:",
22071 return HANDLER_ERROR;
22075 - log_error_write(srv, __FILE__, __LINE__, "s",
22076 + log_error_write(srv, __FILE__, __LINE__, "s",
22077 "memcache support is not compiled in but cml.memcache-hosts is set, aborting");
22078 return HANDLER_ERROR;
22084 return HANDLER_GO_ON;
22087 -#define PATCH(x) \
22088 - p->conf.x = s->x;
22089 static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p) {
22091 plugin_config *s = p->config_storage[0];
22095 + PATCH_OPTION(ext);
22096 #if defined(HAVE_MEMCACHE_H)
22098 + PATCH_OPTION(mc);
22100 - PATCH(mc_namespace);
22101 - PATCH(power_magnet);
22103 + PATCH_OPTION(mc_namespace);
22104 + PATCH_OPTION(power_magnet);
22106 /* skip the first, the global context */
22107 for (i = 1; i < srv->config_context->used; i++) {
22108 data_config *dc = (data_config *)srv->config_context->data[i];
22109 s = p->config_storage[i];
22112 /* condition didn't match */
22113 if (!config_check_cond(srv, con, dc)) continue;
22117 for (j = 0; j < dc->value->used; j++) {
22118 data_unset *du = dc->value->data[j];
22121 if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.extension"))) {
22123 + PATCH_OPTION(ext);
22124 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-hosts"))) {
22125 #if defined(HAVE_MEMCACHE_H)
22127 + PATCH_OPTION(mc);
22129 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-namespace"))) {
22130 - PATCH(mc_namespace);
22131 + PATCH_OPTION(mc_namespace);
22132 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.power-magnet"))) {
22133 - PATCH(power_magnet);
22134 + PATCH_OPTION(power_magnet);
22144 int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
22146 @@ -187,57 +183,57 @@
22148 buffer_copy_string_buffer(b, con->uri.path);
22149 for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
22153 b->used = c - b->ptr + 2;
22159 buffer_copy_string_buffer(b, con->physical.path);
22160 for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
22164 b->used = c - b->ptr + 2;
22170 /* prepare variables
22172 * - get-param-based
22176 return cache_parse_lua(srv, con, p, cml_file);
22181 URIHANDLER_FUNC(mod_cml_power_magnet) {
22182 plugin_data *p = p_d;
22185 mod_cml_patch_connection(srv, con, p);
22188 buffer_reset(p->basedir);
22189 buffer_reset(p->baseurl);
22190 buffer_reset(p->trigger_handler);
22192 if (buffer_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
22198 * cml.power-magnet = server.docroot + "/rewrite.cml"
22200 * is called on EACH request, take the original REQUEST_URI and modifies the
22201 - * request header as neccesary.
22202 + * request header as neccesary.
22205 * if file_exists("/maintainance.html") {
22206 * output_include = ( "/maintainance.html" )
22207 - * return CACHE_HIT
22208 + * return CACHE_HIT
22211 * as we only want to rewrite HTML like requests we should cover it in a conditional
22216 switch(cache_call_lua(srv, con, p, p->conf.power_magnet)) {
22217 @@ -266,20 +262,20 @@
22219 URIHANDLER_FUNC(mod_cml_is_handled) {
22220 plugin_data *p = p_d;
22223 if (buffer_is_empty(con->physical.path)) return HANDLER_ERROR;
22226 mod_cml_patch_connection(srv, con, p);
22229 buffer_reset(p->basedir);
22230 buffer_reset(p->baseurl);
22231 buffer_reset(p->trigger_handler);
22233 if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON;
22236 if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, p->conf.ext->used - 1)) {
22237 return HANDLER_GO_ON;
22241 switch(cache_call_lua(srv, con, p, con->physical.path)) {
22243 @@ -311,15 +307,15 @@
22244 int mod_cml_plugin_init(plugin *p) {
22245 p->version = LIGHTTPD_VERSION_ID;
22246 p->name = buffer_init_string("cache");
22249 p->init = mod_cml_init;
22250 p->cleanup = mod_cml_free;
22251 p->set_defaults = mod_cml_set_defaults;
22253 - p->handle_subrequest_start = mod_cml_is_handled;
22255 + p->handle_start_backend = mod_cml_is_handled;
22256 p->handle_physical = mod_cml_power_magnet;
22264 --- ../lighttpd-1.4.11/src/mod_cml.h 2006-01-30 13:51:35.000000000 +0200
22265 +++ lighttpd-1.5.0/src/mod_cml.h 2006-07-16 00:26:03.000000000 +0300
22266 @@ -16,10 +16,10 @@
22273 buffer *mc_namespace;
22274 -#if defined(HAVE_MEMCACHE_H)
22275 +#if defined(HAVE_MEMCACHE_H)
22276 struct memcache *mc;
22278 buffer *power_magnet;
22279 @@ -27,15 +27,15 @@
22289 buffer *trigger_handler;
22292 plugin_config **config_storage;
22294 - plugin_config conf;
22296 + plugin_config conf;
22299 int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn);
22300 --- ../lighttpd-1.4.11/src/mod_cml_funcs.c 2005-11-17 16:15:08.000000000 +0200
22301 +++ lighttpd-1.5.0/src/mod_cml_funcs.c 2006-07-16 00:26:04.000000000 +0300
22303 #include <stdlib.h>
22304 #include <string.h>
22306 -#include <unistd.h>
22307 -#include <dirent.h>
22311 #include "buffer.h"
22314 #include "plugin.h"
22315 #include "response.h"
22316 +#include "sys-files.h"
22318 #include "mod_cml.h"
22319 #include "mod_cml_funcs.h"
22329 @@ -42,29 +42,29 @@
22332 int n = lua_gettop(L);
22337 b.size = sizeof(hex);
22341 lua_pushstring(L, "md5: expected one argument");
22346 if (!lua_isstring(L, 1)) {
22347 lua_pushstring(L, "md5: argument has to be a string");
22353 MD5_Update(&Md5Ctx, (unsigned char *)lua_tostring(L, 1), lua_strlen(L, 1));
22354 MD5_Final(HA1, &Md5Ctx);
22357 buffer_copy_string_hex(&b, (char *)HA1, 16);
22360 lua_pushstring(L, b.ptr);
22366 @@ -72,37 +72,37 @@
22367 int f_file_mtime(lua_State *L) {
22369 int n = lua_gettop(L);
22373 lua_pushstring(L, "file_mtime: expected one argument");
22378 if (!lua_isstring(L, 1)) {
22379 lua_pushstring(L, "file_mtime: argument has to be a string");
22384 if (-1 == stat(lua_tostring(L, 1), &st)) {
22390 lua_pushnumber(L, st.st_mtime);
22397 int f_dir_files_iter(lua_State *L) {
22402 d = lua_touserdata(L, lua_upvalueindex(1));
22405 if (NULL == (de = readdir(d))) {
22412 lua_pushstring(L, de->d_name);
22413 @@ -113,75 +113,75 @@
22414 int f_dir_files(lua_State *L) {
22416 int n = lua_gettop(L);
22420 lua_pushstring(L, "dir_files: expected one argument");
22425 if (!lua_isstring(L, 1)) {
22426 lua_pushstring(L, "dir_files: argument has to be a string");
22430 - /* check if there is a valid DIR handle on the stack */
22432 + /* check if there is a valid DIR handle on the stack */
22433 if (NULL == (d = opendir(lua_tostring(L, 1)))) {
22439 /* push d into registry */
22440 lua_pushlightuserdata(L, d);
22441 lua_pushcclosure(L, f_dir_files_iter, 1);
22448 int f_file_isreg(lua_State *L) {
22450 int n = lua_gettop(L);
22454 lua_pushstring(L, "file_isreg: expected one argument");
22459 if (!lua_isstring(L, 1)) {
22460 lua_pushstring(L, "file_isreg: argument has to be a string");
22465 if (-1 == stat(lua_tostring(L, 1), &st)) {
22471 lua_pushnumber(L, S_ISREG(st.st_mode));
22477 int f_file_isdir(lua_State *L) {
22479 int n = lua_gettop(L);
22483 lua_pushstring(L, "file_isreg: expected one argument");
22488 if (!lua_isstring(L, 1)) {
22489 lua_pushstring(L, "file_isreg: argument has to be a string");
22494 if (-1 == stat(lua_tostring(L, 1), &st)) {
22500 lua_pushnumber(L, S_ISDIR(st.st_mode));
22506 @@ -192,33 +192,33 @@
22508 int n = lua_gettop(L);
22509 struct memcache *mc;
22512 if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
22513 lua_pushstring(L, "where is my userdata ?");
22518 mc = lua_touserdata(L, lua_upvalueindex(1));
22522 lua_pushstring(L, "expected one argument");
22527 if (!lua_isstring(L, 1)) {
22528 lua_pushstring(L, "argument has to be a string");
22532 - if (NULL == (r = mc_aget(mc,
22534 + if (NULL == (r = mc_aget(mc,
22535 lua_tostring(L, 1), lua_strlen(L, 1)))) {
22538 lua_pushboolean(L, 0);
22546 lua_pushboolean(L, 1);
22549 @@ -226,74 +226,74 @@
22550 int f_memcache_get_string(lua_State *L) {
22552 int n = lua_gettop(L);
22555 struct memcache *mc;
22558 if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
22559 lua_pushstring(L, "where is my userdata ?");
22564 mc = lua_touserdata(L, lua_upvalueindex(1));
22570 lua_pushstring(L, "expected one argument");
22575 if (!lua_isstring(L, 1)) {
22576 lua_pushstring(L, "argument has to be a string");
22580 - if (NULL == (r = mc_aget(mc,
22582 + if (NULL == (r = mc_aget(mc,
22583 lua_tostring(L, 1), lua_strlen(L, 1)))) {
22589 lua_pushstring(L, r);
22598 int f_memcache_get_long(lua_State *L) {
22600 int n = lua_gettop(L);
22603 struct memcache *mc;
22606 if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
22607 lua_pushstring(L, "where is my userdata ?");
22612 mc = lua_touserdata(L, lua_upvalueindex(1));
22618 lua_pushstring(L, "expected one argument");
22623 if (!lua_isstring(L, 1)) {
22624 lua_pushstring(L, "argument has to be a string");
22628 - if (NULL == (r = mc_aget(mc,
22630 + if (NULL == (r = mc_aget(mc,
22631 lua_tostring(L, 1), lua_strlen(L, 1)))) {
22637 lua_pushnumber(L, strtol(r, NULL, 10));
22646 --- ../lighttpd-1.4.11/src/mod_cml_lua.c 2006-01-30 13:56:40.000000000 +0200
22647 +++ lighttpd-1.5.0/src/mod_cml_lua.c 2006-09-07 00:57:05.000000000 +0300
22660 #include <lualib.h>
22661 +#include <lauxlib.h>
22665 @@ -39,11 +40,11 @@
22667 static const char * load_file(lua_State *L, void *data, size_t *size) {
22674 if (rm->done) return 0;
22677 *size = rm->st.size;
22679 return rm->st.start;
22680 @@ -51,47 +52,47 @@
22682 static int lua_to_c_get_string(lua_State *L, const char *varname, buffer *b) {
22686 lua_pushstring(L, varname);
22689 curelem = lua_gettop(L);
22690 lua_gettable(L, LUA_GLOBALSINDEX);
22693 /* it should be a table */
22694 if (!lua_isstring(L, curelem)) {
22695 lua_settop(L, curelem - 1);
22702 buffer_copy_string(b, lua_tostring(L, curelem));
22708 assert(curelem - 1 == lua_gettop(L));
22714 static int lua_to_c_is_table(lua_State *L, const char *varname) {
22718 lua_pushstring(L, varname);
22721 curelem = lua_gettop(L);
22722 lua_gettable(L, LUA_GLOBALSINDEX);
22725 /* it should be a table */
22726 if (!lua_istable(L, curelem)) {
22727 lua_settop(L, curelem - 1);
22734 lua_settop(L, curelem - 1);
22737 assert(curelem - 1 == lua_gettop(L));
22744 lua_pushlstring(L, key, key_len);
22745 lua_pushlstring(L, val, val_len);
22746 lua_settable(L, tbl);
22752 @@ -108,21 +109,21 @@
22755 char *key = NULL, *val = NULL;
22761 /* we need the \0 */
22762 for (i = 0; i < qrystr->used; i++) {
22763 switch(qrystr->ptr[i]) {
22766 val = qrystr->ptr + i + 1;
22769 qrystr->ptr[i] = '\0';
22778 case '\0': /* fin symbol */
22779 @@ -131,19 +132,19 @@
22781 /* terminate the value */
22782 qrystr->ptr[i] = '\0';
22784 - c_to_lua_push(L, tbl,
22786 + c_to_lua_push(L, tbl,
22792 key = qrystr->ptr + i + 1;
22803 @@ -151,21 +152,21 @@
22809 if (NULL != (d = array_get_element(con->request.headers, "Cookie"))) {
22810 data_string *ds = (data_string *)d;
22811 size_t key = 0, value = 0;
22812 size_t is_key = 1, is_sid = 0;
22817 if (!DATA_IS_STRING(d)) return -1;
22818 if (ds->value->used == 0) return -1;
22821 if (ds->value->ptr[0] == '\0' ||
22822 ds->value->ptr[0] == '=' ||
22823 ds->value->ptr[0] == ';') return -1;
22826 buffer_reset(p->session_id);
22827 for (i = 0; i < ds->value->used; i++) {
22828 switch(ds->value->ptr[i]) {
22829 @@ -176,16 +177,16 @@
22842 buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value);
22849 @@ -204,48 +205,43 @@
22859 int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
22864 buffer *b = buffer_init();
22865 int header_tbl = 0;
22869 stream_open(&rm.st, fn);
22872 /* push the lua file to the interpreter and see what happends */
22876 - luaopen_table(L);
22877 - luaopen_string(L);
22881 + L = luaL_newstate();
22882 + luaL_openlibs(L);
22884 /* register functions */
22885 lua_register(L, "md5", f_crypto_md5);
22886 lua_register(L, "file_mtime", f_file_mtime);
22887 lua_register(L, "file_isreg", f_file_isreg);
22888 lua_register(L, "file_isdir", f_file_isreg);
22889 lua_register(L, "dir_files", f_dir_files);
22892 #ifdef HAVE_MEMCACHE_H
22893 lua_pushliteral(L, "memcache_get_long");
22894 lua_pushlightuserdata(L, p->conf.mc);
22895 lua_pushcclosure(L, f_memcache_get_long, 1);
22896 lua_settable(L, LUA_GLOBALSINDEX);
22899 lua_pushliteral(L, "memcache_get_string");
22900 lua_pushlightuserdata(L, p->conf.mc);
22901 lua_pushcclosure(L, f_memcache_get_string, 1);
22902 lua_settable(L, LUA_GLOBALSINDEX);
22905 lua_pushliteral(L, "memcache_exists");
22906 lua_pushlightuserdata(L, p->conf.mc);
22907 lua_pushcclosure(L, f_memcache_exists, 1);
22908 @@ -255,11 +251,11 @@
22909 lua_pushliteral(L, "request");
22911 lua_settable(L, LUA_GLOBALSINDEX);
22914 lua_pushliteral(L, "request");
22915 header_tbl = lua_gettop(L);
22916 lua_gettable(L, LUA_GLOBALSINDEX);
22919 c_to_lua_push(L, header_tbl, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
22920 c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
22921 c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
22922 @@ -267,84 +263,84 @@
22923 if (!buffer_is_empty(con->request.pathinfo)) {
22924 c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
22928 c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir));
22929 c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl));
22932 /* register GET parameter */
22933 lua_pushliteral(L, "get");
22935 lua_settable(L, LUA_GLOBALSINDEX);
22938 lua_pushliteral(L, "get");
22939 header_tbl = lua_gettop(L);
22940 lua_gettable(L, LUA_GLOBALSINDEX);
22943 buffer_copy_string_buffer(b, con->uri.query);
22944 cache_export_get_params(L, header_tbl, b);
22947 - /* 2 default constants */
22948 + /* 2 default constants */
22949 lua_pushliteral(L, "CACHE_HIT");
22950 lua_pushboolean(L, 0);
22951 lua_settable(L, LUA_GLOBALSINDEX);
22954 lua_pushliteral(L, "CACHE_MISS");
22955 lua_pushboolean(L, 1);
22956 lua_settable(L, LUA_GLOBALSINDEX);
22959 /* load lua program */
22960 if (lua_load(L, load_file, &rm, fn->ptr) || lua_pcall(L,0,1,0)) {
22961 log_error_write(srv, __FILE__, __LINE__, "s",
22962 lua_tostring(L,-1));
22969 /* get return value */
22970 ret = (int)lua_tonumber(L, -1);
22973 - /* fetch the data from lua */
22975 + /* fetch the data from lua */
22976 lua_to_c_get_string(L, "trigger_handler", p->trigger_handler);
22979 if (0 == lua_to_c_get_string(L, "output_contenttype", b)) {
22980 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b));
22985 /* up to now it is a cache-hit, check if all files exist */
22992 if (!lua_to_c_is_table(L, "output_include")) {
22993 log_error_write(srv, __FILE__, __LINE__, "s",
22994 "output_include is missing or not a table");
23002 lua_pushstring(L, "output_include");
23005 curelem = lua_gettop(L);
23006 lua_gettable(L, LUA_GLOBALSINDEX);
23008 /* HOW-TO build a etag ?
23009 - * as we don't just have one file we have to take the stat()
23010 + * as we don't just have one file we have to take the stat()
23011 * from all base files, merge them and build the etag from
23015 * The mtime of the content is the mtime of the freshest base file
23021 lua_pushnil(L); /* first key */
23022 while (lua_next(L, curelem) != 0) {
23023 stat_cache_entry *sce = NULL;
23024 /* key' is at index -2 and value' at index -1 */
23027 if (lua_isstring(L, -1)) {
23028 const char *s = lua_tostring(L, -1);
23030 @@ -364,18 +360,18 @@
23031 /* a file is missing, call the handler to generate it */
23032 if (!buffer_is_empty(p->trigger_handler)) {
23033 ret = 1; /* cache-miss */
23036 log_error_write(srv, __FILE__, __LINE__, "s",
23037 "a file is missing, calling handler");
23042 /* handler not set -> 500 */
23046 log_error_write(srv, __FILE__, __LINE__, "s",
23047 "a file missing and no handler set");
23053 @@ -383,7 +379,7 @@
23057 - chunkqueue_append_file(con->write_queue, b, 0, sce->st.st_size);
23058 + chunkqueue_append_file(con->send, b, 0, sce->st.st_size);
23059 if (sce->st.st_mtime > mtime) mtime = sce->st.st_mtime;
23062 @@ -393,26 +389,26 @@
23068 lua_pop(L, 1); /* removes value'; keeps key' for next iteration */
23072 lua_settop(L, curelem - 1);
23077 char timebuf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
23080 - con->file_finished = 1;
23081 + con->send->is_closed = 1;
23083 ds = (data_string *)array_get_element(con->response.headers, "Last-Modified");
23085 /* no Last-Modified specified */
23086 if ((mtime) && (NULL == ds)) {
23089 strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime));
23092 response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), timebuf, sizeof(timebuf) - 1);
23095 @@ -428,36 +424,36 @@
23101 if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, &tbuf)) {
23102 - /* ok, the client already has our content,
23103 + /* ok, the client already has our content,
23104 * no need to send it again */
23106 - chunkqueue_reset(con->write_queue);
23107 + chunkqueue_reset(con->send);
23108 ret = 0; /* cache-hit */
23111 - chunkqueue_reset(con->write_queue);
23112 + chunkqueue_reset(con->send);
23117 if (ret == 1 && !buffer_is_empty(p->trigger_handler)) {
23119 buffer_copy_string_buffer(con->uri.path, p->baseurl);
23120 buffer_append_string_buffer(con->uri.path, p->trigger_handler);
23123 buffer_copy_string_buffer(con->physical.path, p->basedir);
23124 buffer_append_string_buffer(con->physical.path, p->trigger_handler);
23126 - chunkqueue_reset(con->write_queue);
23128 + chunkqueue_reset(con->send);
23136 stream_close(&rm.st);
23140 return ret /* cache-error */;
23143 --- ../lighttpd-1.4.11/src/mod_compress.c 2005-11-18 13:49:14.000000000 +0200
23144 +++ lighttpd-1.5.0/src/mod_compress.c 2006-09-07 00:57:05.000000000 +0300
23146 #include <sys/stat.h>
23149 -#include <unistd.h>
23151 #include <stdlib.h>
23152 #include <string.h>
23156 #include "sys-mmap.h"
23157 +#include "sys-files.h"
23159 /* request: accept-encoding */
23160 #define HTTP_ACCEPT_ENCODING_IDENTITY BV(0)
23161 @@ -55,97 +55,127 @@
23167 plugin_config **config_storage;
23168 - plugin_config conf;
23169 + plugin_config conf;
23172 INIT_FUNC(mod_compress_init) {
23176 p = calloc(1, sizeof(*p));
23179 p->ofn = buffer_init();
23180 p->b = buffer_init();
23186 FREE_FUNC(mod_compress_free) {
23187 plugin_data *p = p_d;
23192 if (!p) return HANDLER_GO_ON;
23195 buffer_free(p->ofn);
23199 if (p->config_storage) {
23201 for (i = 0; i < srv->config_context->used; i++) {
23202 plugin_config *s = p->config_storage[i];
23207 array_free(s->compress);
23208 buffer_free(s->compress_cache_dir);
23213 free(p->config_storage);
23222 return HANDLER_GO_ON;
23225 +void mkdir_recursive(const char *dir) {
23227 + char dir_copy[256];
23228 + char *p = dir_copy;
23230 + if (!dir || !dir[0])
23233 + strncpy(dir_copy, dir, sizeof(dir_copy) / sizeof(dir_copy[0]));
23235 + while ((p = strchr(p + 1, '/')) != NULL) {
23238 + if ((mkdir(dir_copy, 0700) != 0) && (errno != EEXIST))
23244 + mkdir(dir, 0700);
23247 SETDEFAULTS_FUNC(mod_compress_setdefaults) {
23248 plugin_data *p = p_d;
23251 - config_values_t cv[] = {
23253 + config_values_t cv[] = {
23254 { "compress.cache-dir", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
23255 { "compress.filetype", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
23256 { "compress.max-filesize", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
23257 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
23261 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
23264 for (i = 0; i < srv->config_context->used; i++) {
23268 s = calloc(1, sizeof(plugin_config));
23269 s->compress_cache_dir = buffer_init();
23270 s->compress = array_init();
23271 s->compress_max_filesize = 0;
23274 cv[0].destination = s->compress_cache_dir;
23275 cv[1].destination = s->compress;
23276 cv[2].destination = &(s->compress_max_filesize);
23279 p->config_storage[i] = s;
23282 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
23283 return HANDLER_ERROR;
23287 if (!buffer_is_empty(s->compress_cache_dir)) {
23289 if (0 != stat(s->compress_cache_dir->ptr, &st)) {
23290 - log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir",
23292 + log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, attempting to create",
23293 s->compress_cache_dir, strerror(errno));
23295 - return HANDLER_ERROR;
23296 + mkdir_recursive(s->compress_cache_dir->ptr);
23298 + if (0 != stat(s->compress_cache_dir->ptr, &st)) {
23300 + log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, create failed",
23301 + s->compress_cache_dir, strerror(errno));
23303 + return HANDLER_ERROR;
23310 return HANDLER_GO_ON;
23316 @@ -153,32 +183,32 @@
23329 - if (Z_OK != deflateInit2(&z,
23331 + if (Z_OK != deflateInit2(&z,
23332 Z_DEFAULT_COMPRESSION,
23335 -MAX_WBITS, /* supress zlib-header */
23337 Z_DEFAULT_STRATEGY)) {
23342 z.next_in = (unsigned char *)start;
23343 z.avail_in = st_size;
23349 buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12 + 18);
23352 /* write gzip header */
23355 c = (unsigned char *)p->b->ptr;
23358 @@ -190,24 +220,24 @@
23359 c[7] = (mtime >> 24) & 0xff;
23360 c[8] = 0x00; /* extra flags */
23361 c[9] = 0x03; /* UNIX */
23365 z.next_out = (unsigned char *)p->b->ptr + p->b->used;
23366 z.avail_out = p->b->size - p->b->used - 8;
23370 if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
23377 p->b->used += z.total_out;
23380 crc = generate_crc32c(start, st_size);
23383 c = (unsigned char *)p->b->ptr + p->b->used;
23386 c[0] = (crc >> 0) & 0xff;
23387 c[1] = (crc >> 8) & 0xff;
23388 c[2] = (crc >> 16) & 0xff;
23389 @@ -221,51 +251,51 @@
23390 if (Z_OK != deflateEnd(&z)) {
23398 static int deflate_file_to_buffer_deflate(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
23409 - if (Z_OK != deflateInit2(&z,
23411 + if (Z_OK != deflateInit2(&z,
23412 Z_DEFAULT_COMPRESSION,
23415 -MAX_WBITS, /* supress zlib-header */
23417 Z_DEFAULT_STRATEGY)) {
23423 z.avail_in = st_size;
23427 buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12);
23430 z.next_out = (unsigned char *)p->b->ptr;
23431 z.avail_out = p->b->size;
23435 if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
23442 p->b->used += z.total_out;
23445 if (Z_OK != deflateEnd(&z)) {
23453 @@ -274,48 +304,48 @@
23455 static int deflate_file_to_buffer_bzip2(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
23466 - if (BZ_OK != BZ2_bzCompressInit(&bz,
23468 + if (BZ_OK != BZ2_bzCompressInit(&bz,
23469 9, /* blocksize = 900k */
23471 0)) { /* workFactor: default */
23476 bz.next_in = (char *)start;
23477 bz.avail_in = st_size;
23478 bz.total_in_lo32 = 0;
23479 bz.total_in_hi32 = 0;
23482 buffer_prepare_copy(p->b, (bz.avail_in * 1.1) + 12);
23485 bz.next_out = p->b->ptr;
23486 bz.avail_out = p->b->size;
23487 bz.total_out_lo32 = 0;
23488 bz.total_out_hi32 = 0;
23491 if (BZ_STREAM_END != BZ2_bzCompress(&bz, BZ_FINISH)) {
23492 BZ2_bzCompressEnd(&bz);
23497 /* file is too large for now */
23498 if (bz.total_out_hi32) return -1;
23502 p->b->used = bz.total_out_lo32;
23505 if (BZ_OK != BZ2_bzCompressEnd(&bz)) {
23513 @@ -326,47 +356,50 @@
23515 const char *filename = fn->ptr;
23518 + stat_cache_entry *compressed_sce = NULL;
23520 + if (buffer_is_empty(p->conf.compress_cache_dir)) return -1;
23523 if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
23525 - /* don't mmap files > 128Mb
23528 + /* don't mmap files > 128Mb
23530 * we could use a sliding window, but currently there is no need for it
23534 if (sce->st.st_size > 128 * 1024 * 1024) return -1;
23537 buffer_reset(p->ofn);
23538 buffer_copy_string_buffer(p->ofn, p->conf.compress_cache_dir);
23539 - BUFFER_APPEND_SLASH(p->ofn);
23541 + PATHNAME_APPEND_SLASH(p->ofn);
23543 if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) {
23544 size_t offset = p->ofn->used - 1;
23545 char *dir, *nextdir;
23548 buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1);
23551 buffer_copy_string_buffer(p->b, p->ofn);
23555 for (dir = p->b->ptr + offset; NULL != (nextdir = strchr(dir, '/')); dir = nextdir + 1) {
23559 if (-1 == mkdir(p->b->ptr, 0700)) {
23560 if (errno != EEXIST) {
23561 log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cache-directory", p->b, "failed", strerror(errno));
23572 buffer_append_string_buffer(p->ofn, con->uri.path);
23577 case HTTP_ACCEPT_ENCODING_GZIP:
23578 buffer_append_string(p->ofn, "-gzip-");
23579 @@ -381,55 +414,64 @@
23580 log_error_write(srv, __FILE__, __LINE__, "sd", "unknown compression type", type);
23585 buffer_append_string_buffer(p->ofn, sce->etag);
23589 + if (HANDLER_ERROR != stat_cache_get_entry(srv, con, p->ofn, &compressed_sce)) {
23590 + /* file exists */
23592 + chunkqueue_append_file(con->send_raw, p->ofn, 0, compressed_sce->st.st_size);
23593 + con->send->is_closed = 1;
23598 if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600))) {
23599 if (errno == EEXIST) {
23600 /* cache-entry exists */
23602 - log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache hit");
23604 - buffer_copy_string_buffer(con->physical.path, p->ofn);
23610 - log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cachefile", p->ofn, "failed", strerror(errno));
23613 + log_error_write(srv, __FILE__, __LINE__, "sbss",
23614 + "creating cachefile", p->ofn,
23615 + "failed", strerror(errno));
23620 - log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache miss");
23623 if (-1 == (ifd = open(filename, O_RDONLY | O_BINARY))) {
23624 - log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
23626 + log_error_write(srv, __FILE__, __LINE__, "sbss",
23627 + "opening plain-file", fn,
23628 + "failed", strerror(errno));
23639 if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
23640 - log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
23642 + log_error_write(srv, __FILE__, __LINE__, "sbss",
23644 + "failed", strerror(errno));
23654 - case HTTP_ACCEPT_ENCODING_GZIP:
23655 + case HTTP_ACCEPT_ENCODING_GZIP:
23656 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
23658 - case HTTP_ACCEPT_ENCODING_DEFLATE:
23659 + case HTTP_ACCEPT_ENCODING_DEFLATE:
23660 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
23664 - case HTTP_ACCEPT_ENCODING_BZIP2:
23665 + case HTTP_ACCEPT_ENCODING_BZIP2:
23666 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
23669 @@ -437,26 +479,27 @@
23675 if (-1 == (r = write(ofd, p->b->ptr, p->b->used))) {
23676 - munmap(start, sce->st.st_size);
23677 + munmap(start, sce->st.st_size);
23684 if ((size_t)r != p->b->used) {
23690 munmap(start, sce->st.st_size);
23695 if (ret != 0) return -1;
23697 - buffer_copy_string_buffer(con->physical.path, p->ofn);
23700 + chunkqueue_append_file(con->send_raw, p->ofn, 0, r);
23701 + con->send->is_closed = 1;
23706 @@ -465,43 +508,44 @@
23713 if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
23716 /* don't mmap files > 128M
23719 * we could use a sliding window, but currently there is no need for it
23723 if (sce->st.st_size > 128 * 1024 * 1024) return -1;
23727 if (-1 == (ifd = open(fn->ptr, O_RDONLY | O_BINARY))) {
23728 log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
23735 - if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
23737 + start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0);
23741 + if (MAP_FAILED == start) {
23742 log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
23752 - case HTTP_ACCEPT_ENCODING_GZIP:
23753 + case HTTP_ACCEPT_ENCODING_GZIP:
23754 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
23756 - case HTTP_ACCEPT_ENCODING_DEFLATE:
23757 + case HTTP_ACCEPT_ENCODING_DEFLATE:
23758 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
23762 - case HTTP_ACCEPT_ENCODING_BZIP2:
23763 + case HTTP_ACCEPT_ENCODING_BZIP2:
23764 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
23767 @@ -509,69 +553,64 @@
23773 munmap(start, sce->st.st_size);
23777 if (ret != 0) return -1;
23779 - chunkqueue_reset(con->write_queue);
23780 - b = chunkqueue_get_append_buffer(con->write_queue);
23782 + chunkqueue_reset(con->send);
23783 + b = chunkqueue_get_append_buffer(con->send);
23784 buffer_copy_memory(b, p->b->ptr, p->b->used + 1);
23787 buffer_reset(con->physical.path);
23789 - con->file_finished = 1;
23791 + con->send->is_closed = 1;
23792 con->file_started = 1;
23799 -#define PATCH(x) \
23800 - p->conf.x = s->x;
23801 static int mod_compress_patch_connection(server *srv, connection *con, plugin_data *p) {
23803 plugin_config *s = p->config_storage[0];
23805 - PATCH(compress_cache_dir);
23807 - PATCH(compress_max_filesize);
23809 + PATCH_OPTION(compress_cache_dir);
23810 + PATCH_OPTION(compress);
23811 + PATCH_OPTION(compress_max_filesize);
23813 /* skip the first, the global context */
23814 for (i = 1; i < srv->config_context->used; i++) {
23815 data_config *dc = (data_config *)srv->config_context->data[i];
23816 s = p->config_storage[i];
23819 /* condition didn't match */
23820 if (!config_check_cond(srv, con, dc)) continue;
23824 for (j = 0; j < dc->value->used; j++) {
23825 data_unset *du = dc->value->data[j];
23828 if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.cache-dir"))) {
23829 - PATCH(compress_cache_dir);
23830 + PATCH_OPTION(compress_cache_dir);
23831 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.filetype"))) {
23833 + PATCH_OPTION(compress);
23834 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.max-filesize"))) {
23835 - PATCH(compress_max_filesize);
23836 + PATCH_OPTION(compress_max_filesize);
23846 PHYSICALPATH_FUNC(mod_compress_physical) {
23847 plugin_data *p = p_d;
23850 stat_cache_entry *sce = NULL;
23853 /* only GET and POST can get compressed */
23854 - if (con->request.http_method != HTTP_METHOD_GET &&
23855 + if (con->request.http_method != HTTP_METHOD_GET &&
23856 con->request.http_method != HTTP_METHOD_POST) {
23857 return HANDLER_GO_ON;
23859 @@ -579,46 +618,49 @@
23860 if (buffer_is_empty(con->physical.path)) {
23861 return HANDLER_GO_ON;
23865 mod_compress_patch_connection(srv, con, p);
23868 max_fsize = p->conf.compress_max_filesize;
23870 stat_cache_get_entry(srv, con, con->physical.path, &sce);
23872 /* don't compress files that are too large as we need to much time to handle them */
23873 if (max_fsize && (sce->st.st_size >> 10) > max_fsize) return HANDLER_GO_ON;
23876 + /* compressing the file might lead to larger files instead */
23877 + if (sce->st.st_size < 128) return HANDLER_GO_ON;
23879 /* check if mimetype is in compress-config */
23880 for (m = 0; m < p->conf.compress->used; m++) {
23881 data_string *compress_ds = (data_string *)p->conf.compress->data[m];
23884 if (!compress_ds) {
23885 log_error_write(srv, __FILE__, __LINE__, "sbb", "evil", con->physical.path, con->uri.path);
23888 return HANDLER_GO_ON;
23892 if (buffer_is_equal(compress_ds->value, sce->content_type)) {
23893 /* mimetype found */
23897 /* the response might change according to Accept-Encoding */
23898 response_header_insert(srv, con, CONST_STR_LEN("Vary"), CONST_STR_LEN("Accept-Encoding"));
23901 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Encoding"))) {
23902 int accept_encoding = 0;
23903 char *value = ds->value->ptr;
23904 int srv_encodings = 0;
23905 int matched_encodings = 0;
23908 /* get client side support encodings */
23909 if (NULL != strstr(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
23910 if (NULL != strstr(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
23911 if (NULL != strstr(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS;
23912 if (NULL != strstr(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
23913 if (NULL != strstr(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY;
23916 /* get server side supported ones */
23918 srv_encodings |= HTTP_ACCEPT_ENCODING_BZIP2;
23919 @@ -627,18 +669,31 @@
23920 srv_encodings |= HTTP_ACCEPT_ENCODING_GZIP;
23921 srv_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
23925 /* find matching entries */
23926 matched_encodings = accept_encoding & srv_encodings;
23929 if (matched_encodings) {
23930 const char *dflt_gzip = "gzip";
23931 const char *dflt_deflate = "deflate";
23932 const char *dflt_bzip2 = "bzip2";
23935 const char *compression_name = NULL;
23936 int compression_type = 0;
23940 + mtime = strftime_cache_get(srv, sce->st.st_mtime);
23941 + etag_mutate(con->physical.etag, sce->etag);
23943 + response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
23944 + response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
23946 + /* perhaps we don't even have to compress the file as the browser still has the
23947 + * current version */
23948 + if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
23949 + return HANDLER_FINISHED;
23952 /* select best matching encoding */
23953 if (matched_encodings & HTTP_ACCEPT_ENCODING_BZIP2) {
23954 compression_type = HTTP_ACCEPT_ENCODING_BZIP2;
23955 @@ -650,31 +705,21 @@
23956 compression_type = HTTP_ACCEPT_ENCODING_DEFLATE;
23957 compression_name = dflt_deflate;
23961 - if (p->conf.compress_cache_dir->used) {
23962 - if (0 == deflate_file_to_file(srv, con, p,
23963 - con->physical.path, sce, compression_type)) {
23966 - response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
23968 - mtime = strftime_cache_get(srv, sce->st.st_mtime);
23969 - response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
23971 - etag_mutate(con->physical.etag, sce->etag);
23972 - response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
23974 - response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
23976 - return HANDLER_GO_ON;
23978 - } else if (0 == deflate_file_to_buffer(srv, con, p,
23979 - con->physical.path, sce, compression_type)) {
23981 - response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
23982 - response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
23985 + /* deflate it to file (cached) or to memory */
23986 + if (0 == deflate_file_to_file(srv, con, p,
23987 + con->physical.path, sce, compression_type) ||
23988 + 0 == deflate_file_to_buffer(srv, con, p,
23989 + con->physical.path, sce, compression_type)) {
23991 + response_header_overwrite(srv, con,
23992 + CONST_STR_LEN("Content-Encoding"),
23993 + compression_name, strlen(compression_name));
23995 + response_header_overwrite(srv, con,
23996 + CONST_STR_LEN("Content-Type"),
23997 + CONST_BUF_LEN(sce->content_type));
23999 return HANDLER_FINISHED;
24002 @@ -682,20 +727,23 @@
24008 return HANDLER_GO_ON;
24011 int mod_compress_plugin_init(plugin *p) {
24012 p->version = LIGHTTPD_VERSION_ID;
24013 p->name = buffer_init_string("compress");
24016 p->init = mod_compress_init;
24017 p->set_defaults = mod_compress_setdefaults;
24018 - p->handle_subrequest_start = mod_compress_physical;
24020 + /* we have to hook into the response-header settings */
24021 + p->handle_response_header = mod_compress_physical;
24023 p->cleanup = mod_compress_free;
24031 --- ../lighttpd-1.4.11/src/mod_dirlisting.c 2006-01-13 00:00:45.000000000 +0200
24032 +++ lighttpd-1.5.0/src/mod_dirlisting.c 2006-09-07 00:57:05.000000000 +0300
24035 #include <stdlib.h>
24036 #include <string.h>
24037 -#include <dirent.h>
24038 #include <assert.h>
24041 -#include <unistd.h>
24046 #include "response.h"
24047 #include "stat_cache.h"
24048 #include "stream.h"
24051 +#include "sys-strings.h"
24054 * this is a dirlisting for a lighttpd plugin
24055 @@ -27,10 +28,13 @@
24056 #include <sys/syslimits.h>
24059 -#ifdef HAVE_ATTR_ATTRIBUTES_H
24061 #include <attr/attributes.h>
24064 +#include "sys-files.h"
24065 +#include "sys-strings.h"
24067 /* plugin config for all request/connections */
24071 unsigned short hide_readme_file;
24072 unsigned short show_header;
24073 unsigned short hide_header_file;
24076 excludes_buffer *excludes;
24078 buffer *external_css;
24079 @@ -63,13 +67,14 @@
24086 buffer *content_charset;
24090 plugin_config **config_storage;
24092 - plugin_config conf;
24094 + plugin_config conf;
24097 excludes_buffer *excludes_buffer_init(void) {
24098 @@ -146,44 +151,46 @@
24099 /* init the plugin data */
24100 INIT_FUNC(mod_dirlisting_init) {
24104 p = calloc(1, sizeof(*p));
24106 p->tmp_buf = buffer_init();
24107 p->content_charset = buffer_init();
24109 + p->path = buffer_init();
24114 /* detroy the plugin data */
24115 FREE_FUNC(mod_dirlisting_free) {
24116 plugin_data *p = p_d;
24121 if (!p) return HANDLER_GO_ON;
24124 if (p->config_storage) {
24126 for (i = 0; i < srv->config_context->used; i++) {
24127 plugin_config *s = p->config_storage[i];
24133 excludes_buffer_free(s->excludes);
24134 buffer_free(s->external_css);
24135 buffer_free(s->encoding);
24140 free(p->config_storage);
24144 buffer_free(p->tmp_buf);
24145 + buffer_free(p->path);
24146 buffer_free(p->content_charset);
24152 return HANDLER_GO_ON;
24155 @@ -215,10 +222,10 @@
24156 if (0 != excludes_buffer_append(s->excludes,
24157 ((data_string *)(da->value->data[j]))->value)) {
24159 - log_error_write(srv, __FILE__, __LINE__, "sb",
24160 + log_error_write(srv, __FILE__, __LINE__, "sb",
24161 "pcre-compile failed for", ((data_string *)(da->value->data[j]))->value);
24163 - log_error_write(srv, __FILE__, __LINE__, "s",
24164 + log_error_write(srv, __FILE__, __LINE__, "s",
24165 "pcre support is missing, please install libpcre and the headers");
24168 @@ -233,8 +240,8 @@
24169 SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
24170 plugin_data *p = p_d;
24173 - config_values_t cv[] = {
24175 + config_values_t cv[] = {
24176 { "dir-listing.exclude", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
24177 { "dir-listing.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
24178 { "dir-listing.hide-dotfiles", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
24179 @@ -245,18 +252,18 @@
24180 { "dir-listing.show-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
24181 { "dir-listing.hide-header-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
24182 { "server.dir-listing", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
24185 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
24189 if (!p) return HANDLER_ERROR;
24192 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
24195 for (i = 0; i < srv->config_context->used; i++) {
24200 s = calloc(1, sizeof(plugin_config));
24201 s->excludes = excludes_buffer_init();
24202 s->dir_listing = 0;
24203 @@ -267,7 +274,7 @@
24204 s->show_header = 0;
24205 s->hide_header_file = 0;
24206 s->encoding = buffer_init();
24209 cv[0].destination = s->excludes;
24210 cv[1].destination = &(s->dir_listing);
24211 cv[2].destination = &(s->hide_dot_files);
24212 @@ -292,60 +299,57 @@
24213 return HANDLER_GO_ON;
24216 -#define PATCH(x) \
24217 - p->conf.x = s->x;
24218 static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_data *p) {
24220 plugin_config *s = p->config_storage[0];
24222 - PATCH(dir_listing);
24223 - PATCH(external_css);
24224 - PATCH(hide_dot_files);
24226 - PATCH(show_readme);
24227 - PATCH(hide_readme_file);
24228 - PATCH(show_header);
24229 - PATCH(hide_header_file);
24232 + PATCH_OPTION(dir_listing);
24233 + PATCH_OPTION(external_css);
24234 + PATCH_OPTION(hide_dot_files);
24235 + PATCH_OPTION(encoding);
24236 + PATCH_OPTION(show_readme);
24237 + PATCH_OPTION(hide_readme_file);
24238 + PATCH_OPTION(show_header);
24239 + PATCH_OPTION(hide_header_file);
24240 + PATCH_OPTION(excludes);
24242 /* skip the first, the global context */
24243 for (i = 1; i < srv->config_context->used; i++) {
24244 data_config *dc = (data_config *)srv->config_context->data[i];
24245 s = p->config_storage[i];
24248 /* condition didn't match */
24249 if (!config_check_cond(srv, con, dc)) continue;
24253 for (j = 0; j < dc->value->used; j++) {
24254 data_unset *du = dc->value->data[j];
24257 if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.activate")) ||
24258 buffer_is_equal_string(du->key, CONST_STR_LEN("server.dir-listing"))) {
24259 - PATCH(dir_listing);
24260 + PATCH_OPTION(dir_listing);
24261 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-dotfiles"))) {
24262 - PATCH(hide_dot_files);
24263 + PATCH_OPTION(hide_dot_files);
24264 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.external-css"))) {
24265 - PATCH(external_css);
24266 + PATCH_OPTION(external_css);
24267 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.encoding"))) {
24269 + PATCH_OPTION(encoding);
24270 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-readme"))) {
24271 - PATCH(show_readme);
24272 + PATCH_OPTION(show_readme);
24273 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-readme-file"))) {
24274 - PATCH(hide_readme_file);
24275 + PATCH_OPTION(hide_readme_file);
24276 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-header"))) {
24277 - PATCH(show_header);
24278 + PATCH_OPTION(show_header);
24279 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-header-file"))) {
24280 - PATCH(hide_header_file);
24281 + PATCH_OPTION(hide_header_file);
24282 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.excludes"))) {
24284 + PATCH_OPTION(excludes);
24296 @@ -432,7 +436,7 @@
24298 static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) {
24302 BUFFER_APPEND_STRING_CONST(out,
24303 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
24304 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n"
24305 @@ -492,11 +496,11 @@
24306 if (p->conf.show_header) {
24308 /* if we have a HEADER file, display it in <pre class="header"></pre> */
24311 buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
24312 - BUFFER_APPEND_SLASH(p->tmp_buf);
24313 + PATHNAME_APPEND_SLASH(p->tmp_buf);
24314 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "HEADER.txt");
24317 if (-1 != stream_open(&s, p->tmp_buf)) {
24318 BUFFER_APPEND_STRING_CONST(out, "<pre class=\"header\">");
24319 buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
24320 @@ -531,21 +535,21 @@
24322 static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) {
24326 BUFFER_APPEND_STRING_CONST(out,
24333 if (p->conf.show_readme) {
24335 /* if we have a README file, display it in <pre class="readme"></pre> */
24338 buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
24339 - BUFFER_APPEND_SLASH(p->tmp_buf);
24340 + PATHNAME_APPEND_SLASH(p->tmp_buf);
24341 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "README.txt");
24344 if (-1 != stream_open(&s, p->tmp_buf)) {
24345 BUFFER_APPEND_STRING_CONST(out, "<pre class=\"readme\">");
24346 buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
24347 @@ -553,7 +557,7 @@
24353 BUFFER_APPEND_STRING_CONST(out,
24354 "<div class=\"foot\">"
24356 @@ -576,7 +580,6 @@
24358 struct dirent *dent;
24360 - char *path, *path_file;
24362 int hide_dotfiles = p->conf.hide_dot_files;
24363 dirls_list_t dirs, files, *list;
24364 @@ -586,6 +589,7 @@
24366 const char *content_type;
24372 @@ -594,10 +598,10 @@
24376 - if (dir->used == 0) return -1;
24378 - i = dir->used - 1;
24379 + /* empty pathname, never ... */
24380 + if (buffer_is_empty(dir)) return -1;
24382 + /* max-length for the opendir */
24383 #ifdef HAVE_PATHCONF
24384 if (-1 == (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) {
24386 @@ -606,22 +610,24 @@
24387 name_max = 256; /* stupid default */
24390 -#elif defined __WIN32
24391 +#elif defined _WIN32
24392 name_max = FILENAME_MAX;
24394 name_max = NAME_MAX;
24397 - path = malloc(dir->used + name_max);
24399 - strcpy(path, dir->ptr);
24400 - path_file = path + i;
24402 - if (NULL == (dp = opendir(path))) {
24403 - log_error_write(srv, __FILE__, __LINE__, "sbs",
24404 + buffer_copy_string_buffer(p->path, dir);
24405 + PATHNAME_APPEND_SLASH(p->path);
24408 + /* append *.* to the path */
24409 + buffer_append_string(path, "*.*");
24412 + if (NULL == (dp = opendir(p->path->ptr))) {
24413 + log_error_write(srv, __FILE__, __LINE__, "sbs",
24414 "opendir failed:", dir, strerror(errno));
24420 @@ -633,7 +639,7 @@
24422 files.size = DIRLIST_BLOB_SIZE;
24426 while ((dent = readdir(dp)) != NULL) {
24427 unsigned short exclude_match = 0;
24429 @@ -686,15 +692,21 @@
24432 i = strlen(dent->d_name);
24435 /* NOTE: the manual says, d_name is never more than NAME_MAX
24436 * so this should actually not be a buffer-overflow-risk
24438 if (i > (size_t)name_max) continue;
24440 - memcpy(path_file, dent->d_name, i + 1);
24441 - if (stat(path, &st) != 0)
24443 + /* build the dirname */
24444 + buffer_copy_string_buffer(p->path, dir);
24445 + PATHNAME_APPEND_SLASH(p->path);
24446 + buffer_append_string(p->path, dent->d_name);
24448 + if (stat(p->path->ptr, &st) != 0) {
24449 + fprintf(stderr, "%s.%d: %s, %s\r\n", __FILE__, __LINE__, p->path->ptr, strerror(errno));
24454 if (S_ISDIR(st.st_mode))
24455 @@ -720,7 +732,7 @@
24457 if (files.used) http_dirls_sort(files.ent, files.used);
24459 - out = chunkqueue_get_append_buffer(con->write_queue);
24460 + out = chunkqueue_get_append_buffer(con->send);
24461 BUFFER_COPY_STRING_CONST(out, "<?xml version=\"1.0\" encoding=\"");
24462 if (buffer_is_empty(p->conf.encoding)) {
24463 BUFFER_APPEND_STRING_CONST(out, "iso-8859-1");
24464 @@ -740,7 +752,7 @@
24466 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
24470 BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
24471 buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
24472 BUFFER_APPEND_STRING_CONST(out, "/\">");
24473 @@ -757,18 +769,22 @@
24474 tmp = files.ent[i];
24476 content_type = NULL;
24480 if (con->conf.use_xattr) {
24481 - memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
24482 + /* build the dirname */
24483 + buffer_copy_string_buffer(p->path, dir);
24484 + PATHNAME_APPEND_SLASH(p->path);
24485 + buffer_append_string_len(p->path, DIRLIST_ENT_NAME(tmp), tmp->namelen);
24487 attrlen = sizeof(attrval) - 1;
24488 - if (attr_get(path, "Content-Type", attrval, &attrlen, 0) == 0) {
24489 + if (attr_get(p->path->ptr, "Content-Type", attrval, &attrlen, 0) == 0) {
24490 attrval[attrlen] = '\0';
24491 content_type = attrval;
24497 if (content_type == NULL) {
24498 content_type = "application/octet-stream";
24499 for (k = 0; k < con->conf.mimetypes->used; k++) {
24500 @@ -788,7 +804,7 @@
24506 #ifdef HAVE_LOCALTIME_R
24507 localtime_r(&(tmp->mtime), &tm);
24508 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
24509 @@ -814,7 +830,6 @@
24515 http_list_directory_footer(srv, con, p, out);
24517 @@ -827,7 +842,7 @@
24518 response_header_insert(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->content_charset));
24521 - con->file_finished = 1;
24522 + con->send->is_closed = 1;
24526 @@ -837,36 +852,55 @@
24527 URIHANDLER_FUNC(mod_dirlisting_subrequest) {
24528 plugin_data *p = p_d;
24529 stat_cache_entry *sce = NULL;
24533 - if (con->physical.path->used == 0) return HANDLER_GO_ON;
24534 - if (con->uri.path->used == 0) return HANDLER_GO_ON;
24538 + if (con->uri.path->used < 2) return HANDLER_GO_ON;
24539 if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
24541 + if (con->physical.path->used == 0) return HANDLER_GO_ON;
24543 mod_dirlisting_patch_connection(srv, con, p);
24545 if (!p->conf.dir_listing) return HANDLER_GO_ON;
24548 + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
24549 + /* just a second ago the file was still there */
24550 + return HANDLER_GO_ON;
24553 + if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
24555 if (con->conf.log_request_handling) {
24556 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Dir-Listing");
24557 log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
24560 - if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
24561 - fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, con->physical.path->ptr);
24564 + /* perhaps this a cachable request
24565 + * - we use the etag of the directory
24568 + etag_mutate(con->physical.etag, sce->etag);
24569 + response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
24571 + /* prepare header */
24572 + if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
24573 + mtime = strftime_cache_get(srv, sce->st.st_mtime);
24574 + response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
24576 + mtime = ds->value;
24579 - if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
24582 + if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
24583 + return HANDLER_FINISHED;
24586 if (http_list_directory(srv, con, p, con->physical.path)) {
24587 /* dirlisting failed */
24588 con->http_status = 403;
24592 buffer_reset(con->physical.path);
24596 return HANDLER_FINISHED;
24598 @@ -876,13 +910,13 @@
24599 int mod_dirlisting_plugin_init(plugin *p) {
24600 p->version = LIGHTTPD_VERSION_ID;
24601 p->name = buffer_init_string("dirlisting");
24604 p->init = mod_dirlisting_init;
24605 - p->handle_subrequest_start = mod_dirlisting_subrequest;
24606 + p->handle_start_backend = mod_dirlisting_subrequest;
24607 p->set_defaults = mod_dirlisting_set_defaults;
24608 p->cleanup = mod_dirlisting_free;
24616 --- ../lighttpd-1.4.11/src/mod_evasive.c 2006-01-04 15:24:51.000000000 +0200
24617 +++ lighttpd-1.5.0/src/mod_evasive.c 2006-09-07 00:57:05.000000000 +0300
24618 @@ -31,100 +31,97 @@
24624 plugin_config **config_storage;
24626 - plugin_config conf;
24628 + plugin_config conf;
24631 INIT_FUNC(mod_evasive_init) {
24635 p = calloc(1, sizeof(*p));
24641 FREE_FUNC(mod_evasive_free) {
24642 plugin_data *p = p_d;
24647 if (!p) return HANDLER_GO_ON;
24650 if (p->config_storage) {
24652 for (i = 0; i < srv->config_context->used; i++) {
24653 plugin_config *s = p->config_storage[i];
24658 free(p->config_storage);
24665 return HANDLER_GO_ON;
24668 SETDEFAULTS_FUNC(mod_evasive_set_defaults) {
24669 plugin_data *p = p_d;
24672 - config_values_t cv[] = {
24674 + config_values_t cv[] = {
24675 { "evasive.max-conns-per-ip", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
24676 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
24680 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
24683 for (i = 0; i < srv->config_context->used; i++) {
24687 s = calloc(1, sizeof(plugin_config));
24691 cv[0].destination = &(s->max_conns);
24694 p->config_storage[i] = s;
24697 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
24698 return HANDLER_ERROR;
24703 return HANDLER_GO_ON;
24706 -#define PATCH(x) \
24707 - p->conf.x = s->x;
24708 static int mod_evasive_patch_connection(server *srv, connection *con, plugin_data *p) {
24710 plugin_config *s = p->config_storage[0];
24712 - PATCH(max_conns);
24714 + PATCH_OPTION(max_conns);
24716 /* skip the first, the global context */
24717 for (i = 1; i < srv->config_context->used; i++) {
24718 data_config *dc = (data_config *)srv->config_context->data[i];
24719 s = p->config_storage[i];
24722 /* condition didn't match */
24723 if (!config_check_cond(srv, con, dc)) continue;
24727 for (j = 0; j < dc->value->used; j++) {
24728 data_unset *du = dc->value->data[j];
24731 if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.max-conns-per-ip"))) {
24732 - PATCH(max_conns);
24733 + PATCH_OPTION(max_conns);
24743 URIHANDLER_FUNC(mod_evasive_uri_handler) {
24744 plugin_data *p = p_d;
24745 @@ -132,10 +129,10 @@
24748 if (con->uri.path->used == 0) return HANDLER_GO_ON;
24751 mod_evasive_patch_connection(srv, con, p);
24753 - /* no limit set, nothing to block */
24755 + /* no limit set, nothing to block */
24756 if (p->conf.max_conns == 0) return HANDLER_GO_ON;
24758 for (j = 0; j < srv->conns->used; j++) {
24759 @@ -145,9 +142,9 @@
24760 * we can only ban connections which are already behind the 'read request' state
24762 if (c->dst_addr.ipv4.sin_addr.s_addr == con->dst_addr.ipv4.sin_addr.s_addr &&
24763 - c->state > CON_STATE_REQUEST_END) {
24764 + c->state > CON_STATE_HANDLE_REQUEST_HEADER) {
24768 if (conns_by_ip > p->conf.max_conns) {
24769 log_error_write(srv, __FILE__, __LINE__, "ss",
24770 inet_ntop_cache_get_ip(srv, &(con->dst_addr)),
24771 @@ -158,7 +155,7 @@
24777 return HANDLER_GO_ON;
24780 @@ -166,13 +163,13 @@
24781 int mod_evasive_plugin_init(plugin *p) {
24782 p->version = LIGHTTPD_VERSION_ID;
24783 p->name = buffer_init_string("evasive");
24786 p->init = mod_evasive_init;
24787 p->set_defaults = mod_evasive_set_defaults;
24788 p->handle_uri_clean = mod_evasive_uri_handler;
24789 p->cleanup = mod_evasive_free;
24797 --- ../lighttpd-1.4.11/src/mod_evhost.c 2005-08-17 10:42:03.000000000 +0300
24798 +++ lighttpd-1.5.0/src/mod_evhost.c 2006-07-16 00:26:03.000000000 +0300
24800 #include "response.h"
24801 #include "stat_cache.h"
24803 +#include "sys-files.h"
24806 /* unparsed pieces */
24807 buffer *path_pieces_raw;
24810 /* pieces for path creation */
24812 buffer **path_pieces;
24813 @@ -21,14 +23,14 @@
24816 plugin_config **config_storage;
24817 - plugin_config conf;
24818 + plugin_config conf;
24821 INIT_FUNC(mod_evhost_init) {
24825 p = calloc(1, sizeof(*p));
24828 p->tmp_buf = buffer_init();
24831 @@ -36,34 +38,34 @@
24833 FREE_FUNC(mod_evhost_free) {
24834 plugin_data *p = p_d;
24839 if (!p) return HANDLER_GO_ON;
24842 if (p->config_storage) {
24844 for (i = 0; i < srv->config_context->used; i++) {
24845 plugin_config *s = p->config_storage[i];
24850 if(s->path_pieces) {
24852 for (j = 0; j < s->len; j++) {
24853 buffer_free(s->path_pieces[j]);
24857 free(s->path_pieces);
24861 buffer_free(s->path_pieces_raw);
24866 free(p->config_storage);
24870 buffer_free(p->tmp_buf);
24873 @@ -73,30 +75,30 @@
24875 static void mod_evhost_parse_pattern(plugin_config *s) {
24876 char *ptr = s->path_pieces_raw->ptr,*pos;
24879 s->path_pieces = NULL;
24882 for(pos=ptr;*ptr;ptr++) {
24884 s->path_pieces = realloc(s->path_pieces,(s->len+2) * sizeof(*s->path_pieces));
24885 s->path_pieces[s->len] = buffer_init();
24886 s->path_pieces[s->len+1] = buffer_init();
24889 buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
24893 buffer_copy_string_len(s->path_pieces[s->len+1],ptr++,2);
24902 s->path_pieces = realloc(s->path_pieces,(s->len+1) * sizeof(*s->path_pieces));
24903 s->path_pieces[s->len] = buffer_init();
24906 buffer_append_memory(s->path_pieces[s->len],pos,ptr-pos);
24912 @@ -104,9 +106,9 @@
24913 SETDEFAULTS_FUNC(mod_evhost_set_defaults) {
24914 plugin_data *p = p_d;
24922 * # define a pattern for the host url finding
24924 @@ -117,39 +119,39 @@
24925 * # %4 => subdomain 2 name
24927 * evhost.path-pattern = "/home/ckruse/dev/www/%3/htdocs/"
24932 - config_values_t cv[] = {
24934 + config_values_t cv[] = {
24935 { "evhost.path-pattern", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
24936 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
24940 if (!p) return HANDLER_ERROR;
24943 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
24946 for (i = 0; i < srv->config_context->used; i++) {
24950 s = calloc(1, sizeof(plugin_config));
24951 s->path_pieces_raw = buffer_init();
24952 s->path_pieces = NULL;
24956 cv[0].destination = s->path_pieces_raw;
24959 p->config_storage[i] = s;
24962 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
24963 return HANDLER_ERROR;
24967 if (s->path_pieces_raw->used != 0) {
24968 mod_evhost_parse_pattern(s);
24973 return HANDLER_GO_ON;
24976 @@ -158,7 +160,7 @@
24977 * - %0 - full hostname (authority w/o port)
24979 * - %2 - domain.tld
24984 static int mod_evhost_parse_host(connection *con,array *host) {
24985 @@ -168,7 +170,7 @@
24991 /* first, find the domain + tld */
24992 for(;ptr > con->uri.authority->ptr;ptr--) {
24994 @@ -179,18 +181,18 @@
25000 ds = data_string_init();
25001 buffer_copy_string(ds->key,"%0");
25004 /* if we stopped at a dot, skip the dot */
25005 if (*ptr == '.') ptr++;
25006 buffer_copy_string_len(ds->value, ptr, colon-ptr);
25009 array_insert_unique(host,(data_unset *)ds);
25012 /* if the : is not the start of the authority, go on parsing the hostname */
25015 if (colon != con->uri.authority->ptr) {
25016 for(ptr = colon - 1, i = 1; ptr > con->uri.authority->ptr; ptr--) {
25018 @@ -200,59 +202,55 @@
25019 buffer_copy_string(ds->key,"%");
25020 buffer_append_long(ds->key, i++);
25021 buffer_copy_string_len(ds->value,ptr+1,colon-ptr-1);
25024 array_insert_unique(host,(data_unset *)ds);
25031 /* if the . is not the first charactor of the hostname */
25032 if (colon != ptr) {
25033 ds = data_string_init();
25034 buffer_copy_string(ds->key,"%");
25035 buffer_append_long(ds->key, i++);
25036 buffer_copy_string_len(ds->value,ptr,colon-ptr);
25039 array_insert_unique(host,(data_unset *)ds);
25047 -#define PATCH(x) \
25048 - p->conf.x = s->x;
25049 static int mod_evhost_patch_connection(server *srv, connection *con, plugin_data *p) {
25051 plugin_config *s = p->config_storage[0];
25053 - PATCH(path_pieces);
25057 + PATCH_OPTION(path_pieces);
25058 + PATCH_OPTION(len);
25060 /* skip the first, the global context */
25061 for (i = 1; i < srv->config_context->used; i++) {
25062 data_config *dc = (data_config *)srv->config_context->data[i];
25063 s = p->config_storage[i];
25066 /* condition didn't match */
25067 if (!config_check_cond(srv, con, dc)) continue;
25071 for (j = 0; j < dc->value->used; j++) {
25072 data_unset *du = dc->value->data[j];
25075 if (buffer_is_equal_string(du->key, CONST_STR_LEN("evhost.path-pattern"))) {
25076 - PATCH(path_pieces);
25078 + PATCH_OPTION(path_pieces);
25079 + PATCH_OPTION(len);
25090 static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d) {
25091 plugin_data *p = p_d;
25092 @@ -261,29 +259,29 @@
25093 register char *ptr;
25095 stat_cache_entry *sce = NULL;
25098 /* not authority set */
25099 if (con->uri.authority->used == 0) return HANDLER_GO_ON;
25102 mod_evhost_patch_connection(srv, con, p);
25105 /* missing even default(global) conf */
25106 if (0 == p->conf.len) {
25107 return HANDLER_GO_ON;
25110 parsed_host = array_init();
25113 mod_evhost_parse_host(con, parsed_host);
25116 /* build document-root */
25117 buffer_reset(p->tmp_buf);
25120 for (i = 0; i < p->conf.len; i++) {
25121 ptr = p->conf.path_pieces[i]->ptr;
25126 if (*(ptr+1) == '%') {
25128 BUFFER_APPEND_STRING_CONST(p->tmp_buf,"%");
25129 @@ -298,11 +296,11 @@
25130 buffer_append_string_buffer(p->tmp_buf,p->conf.path_pieces[i]);
25134 - BUFFER_APPEND_SLASH(p->tmp_buf);
25137 + PATHNAME_APPEND_SLASH(p->tmp_buf);
25139 array_free(parsed_host);
25142 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
25143 log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
25145 @@ -310,11 +308,11 @@
25146 log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", p->tmp_buf);
25152 buffer_copy_string_buffer(con->physical.doc_root, p->tmp_buf);
25156 return HANDLER_GO_ON;
25159 @@ -325,9 +323,9 @@
25160 p->set_defaults = mod_evhost_set_defaults;
25161 p->handle_docroot = mod_evhost_uri_handler;
25162 p->cleanup = mod_evhost_free;
25171 --- ../lighttpd-1.4.11/src/mod_expire.c 2005-11-03 09:52:13.000000000 +0200
25172 +++ lighttpd-1.5.0/src/mod_expire.c 2006-09-07 00:57:05.000000000 +0300
25174 #include "stat_cache.h"
25177 - * this is a expire module for a lighttpd
25179 + * this is a expire module for a lighttpd
25181 * set 'Expires:' HTTP Headers on demand
25184 @@ -27,51 +27,51 @@
25190 buffer *expire_tstmp;
25193 plugin_config **config_storage;
25195 - plugin_config conf;
25197 + plugin_config conf;
25200 /* init the plugin data */
25201 INIT_FUNC(mod_expire_init) {
25205 p = calloc(1, sizeof(*p));
25208 p->expire_tstmp = buffer_init();
25211 buffer_prepare_copy(p->expire_tstmp, 255);
25217 /* detroy the plugin data */
25218 FREE_FUNC(mod_expire_free) {
25219 plugin_data *p = p_d;
25224 if (!p) return HANDLER_GO_ON;
25227 buffer_free(p->expire_tstmp);
25230 if (p->config_storage) {
25232 for (i = 0; i < srv->config_context->used; i++) {
25233 plugin_config *s = p->config_storage[i];
25236 array_free(s->expire_url);
25241 free(p->config_storage);
25248 return HANDLER_GO_ON;
25251 @@ -79,25 +79,25 @@
25264 * '(access|modification) [plus] {<num> <type>}*'
25267 * e.g. 'access 1 years'
25271 if (expire->used == 0) {
25272 - log_error_write(srv, __FILE__, __LINE__, "s",
25273 + log_error_write(srv, __FILE__, __LINE__, "s",
25282 if (0 == strncmp(ts, "access ", 7)) {
25285 @@ -110,39 +110,39 @@
25286 "invalid <base>:", ts);
25291 if (0 == strncmp(ts, "plus ", 5)) {
25292 /* skip the optional plus */
25297 /* the rest is just <number> (years|months|days|hours|minutes|seconds) */
25303 if (NULL == (space = strchr(ts, ' '))) {
25304 - log_error_write(srv, __FILE__, __LINE__, "ss",
25305 + log_error_write(srv, __FILE__, __LINE__, "ss",
25306 "missing space after <num>:", ts);
25311 num = strtol(ts, &err, 10);
25313 - log_error_write(srv, __FILE__, __LINE__, "ss",
25314 + log_error_write(srv, __FILE__, __LINE__, "ss",
25315 "missing <type> after <num>:", ts);
25323 if (NULL != (space = strchr(ts, ' '))) {
25333 0 == strncmp(ts, "years", slen)) {
25334 num *= 60 * 60 * 24 * 30 * 12;
25335 } else if (slen == 6 &&
25336 @@ -161,13 +161,13 @@
25337 0 == strncmp(ts, "seconds", slen)) {
25340 - log_error_write(srv, __FILE__, __LINE__, "ss",
25341 + log_error_write(srv, __FILE__, __LINE__, "ss",
25342 "unknown type:", ts);
25352 if (0 == strcmp(ts, "years")) {
25353 @@ -183,19 +183,19 @@
25354 } else if (0 == strcmp(ts, "seconds")) {
25357 - log_error_write(srv, __FILE__, __LINE__, "ss",
25358 + log_error_write(srv, __FILE__, __LINE__, "ss",
25359 "unknown type:", ts);
25372 if (offset != NULL) *offset = retts;
25378 @@ -205,102 +205,99 @@
25379 SETDEFAULTS_FUNC(mod_expire_set_defaults) {
25380 plugin_data *p = p_d;
25383 - config_values_t cv[] = {
25385 + config_values_t cv[] = {
25386 { "expire.url", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
25387 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
25391 if (!p) return HANDLER_ERROR;
25394 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
25397 for (i = 0; i < srv->config_context->used; i++) {
25401 s = calloc(1, sizeof(plugin_config));
25402 s->expire_url = array_init();
25405 cv[0].destination = s->expire_url;
25408 p->config_storage[i] = s;
25411 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
25412 return HANDLER_ERROR;
25416 for (k = 0; k < s->expire_url->used; k++) {
25417 data_string *ds = (data_string *)s->expire_url->data[k];
25421 if (-1 == mod_expire_get_offset(srv, p, ds->value, NULL)) {
25422 - log_error_write(srv, __FILE__, __LINE__, "sb",
25423 + log_error_write(srv, __FILE__, __LINE__, "sb",
25424 "parsing expire.url failed:", ds->value);
25425 return HANDLER_ERROR;
25433 return HANDLER_GO_ON;
25436 -#define PATCH(x) \
25437 - p->conf.x = s->x;
25438 static int mod_expire_patch_connection(server *srv, connection *con, plugin_data *p) {
25440 plugin_config *s = p->config_storage[0];
25442 - PATCH(expire_url);
25445 + PATCH_OPTION(expire_url);
25447 /* skip the first, the global context */
25448 for (i = 1; i < srv->config_context->used; i++) {
25449 data_config *dc = (data_config *)srv->config_context->data[i];
25450 s = p->config_storage[i];
25453 /* condition didn't match */
25454 if (!config_check_cond(srv, con, dc)) continue;
25458 for (j = 0; j < dc->value->used; j++) {
25459 data_unset *du = dc->value->data[j];
25462 if (buffer_is_equal_string(du->key, CONST_STR_LEN("expire.url"))) {
25463 - PATCH(expire_url);
25464 + PATCH_OPTION(expire_url);
25474 URIHANDLER_FUNC(mod_expire_path_handler) {
25475 plugin_data *p = p_d;
25480 if (con->uri.path->used == 0) return HANDLER_GO_ON;
25483 mod_expire_patch_connection(srv, con, p);
25486 s_len = con->uri.path->used - 1;
25489 for (k = 0; k < p->conf.expire_url->used; k++) {
25490 data_string *ds = (data_string *)p->conf.expire_url->data[k];
25491 int ct_len = ds->key->used - 1;
25494 if (ct_len > s_len) continue;
25495 if (ds->key->used == 0) continue;
25498 if (0 == strncmp(con->uri.path->ptr, ds->key->ptr, ct_len)) {
25502 stat_cache_entry *sce = NULL;
25505 stat_cache_get_entry(srv, con, con->physical.path, &sce);
25508 switch(mod_expire_get_offset(srv, p, ds->value, &ts)) {
25511 @@ -308,38 +305,38 @@
25517 t = (ts + sce->st.st_mtime);
25520 /* -1 is handled at parse-time */
25525 - if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
25528 + if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
25529 "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(t))))) {
25530 /* could not set expire header, out of mem */
25533 return HANDLER_GO_ON;
25539 p->expire_tstmp->used = len + 1;
25544 response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_BUF_LEN(p->expire_tstmp));
25548 buffer_copy_string(p->expire_tstmp, "max-age=");
25549 buffer_append_long(p->expire_tstmp, ts);
25552 response_header_overwrite(srv, con, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(p->expire_tstmp));
25555 return HANDLER_GO_ON;
25561 return HANDLER_GO_ON;
25563 @@ -349,13 +346,13 @@
25564 int mod_expire_plugin_init(plugin *p) {
25565 p->version = LIGHTTPD_VERSION_ID;
25566 p->name = buffer_init_string("expire");
25569 p->init = mod_expire_init;
25570 - p->handle_subrequest_start = mod_expire_path_handler;
25571 + p->handle_response_header = mod_expire_path_handler;
25572 p->set_defaults = mod_expire_set_defaults;
25573 p->cleanup = mod_expire_free;
25581 --- ../lighttpd-1.4.11/src/mod_fastcgi.c 2006-03-09 13:18:39.000000000 +0200
25582 +++ lighttpd-1.5.0/src/mod_fastcgi.c 2006-09-07 00:57:05.000000000 +0300
25584 #include <sys/types.h>
25585 -#include <unistd.h>
25588 #include <string.h>
25589 @@ -13,18 +12,18 @@
25590 #include "keyvalue.h"
25593 -#include "http_chunk.h"
25594 #include "fdevent.h"
25595 #include "connections.h"
25596 #include "response.h"
25597 #include "joblist.h"
25598 +#include "status_counter.h"
25600 #include "plugin.h"
25602 #include "inet_ntop_cache.h"
25603 #include "stat_cache.h"
25605 -#include <fastcgi.h>
25606 +#include "fastcgi.h"
25609 #ifdef HAVE_SYS_FILIO_H
25613 #include "sys-socket.h"
25614 +#include "sys-files.h"
25615 +#include "sys-strings.h"
25616 +#include "sys-process.h"
25618 +#include "http_resp.h"
25620 #ifndef UNIX_PATH_MAX
25621 # define UNIX_PATH_MAX 108
25622 @@ -45,14 +48,13 @@
25623 #include <sys/wait.h>
25633 * - add timeout for a connect to a non-fastcgi process
25634 * (use state_timestamp + state)
25639 typedef struct fcgi_proc {
25641 unsigned port; /* config.port + pno */
25643 buffer *connection_name; /* either tcp:<host>:<port> or unix:<socket> for debuggin purposes */
25646 pid_t pid; /* PID of the spawned process (0 if not spawned locally) */
25649 @@ -70,20 +72,20 @@
25650 time_t last_used; /* see idle_timeout */
25651 size_t requests; /* see max_requests */
25652 struct fcgi_proc *prev, *next; /* see first */
25655 time_t disabled_until; /* this proc is disabled until, use something else until than */
25662 PROC_STATE_UNSET, /* init-phase */
25663 PROC_STATE_RUNNING, /* alive */
25664 - PROC_STATE_OVERLOADED, /* listen-queue is full,
25665 + PROC_STATE_OVERLOADED, /* listen-queue is full,
25666 don't send something to this proc for the next 2 seconds */
25667 PROC_STATE_DIED_WAIT_FOR_PID, /* */
25668 PROC_STATE_DIED, /* marked as dead, should be restarted */
25669 PROC_STATE_KILLED /* was killed as we don't have the load anymore */
25675 @@ -94,20 +96,20 @@
25676 * sorted by lowest load
25678 * whenever a job is done move it up in the list
25679 - * until it is sorted, move it down as soon as the
25680 + * until it is sorted, move it down as soon as the
25683 - fcgi_proc *first;
25684 - fcgi_proc *unused_procs;
25685 + fcgi_proc *first;
25686 + fcgi_proc *unused_procs;
25690 * spawn at least min_procs, at max_procs.
25692 - * as soon as the load of the first entry
25693 + * as soon as the load of the first entry
25694 * is max_load_per_proc we spawn a new one
25695 - * and add it to the first entry and give it
25696 + * and add it to the first entry and give it
25702 unsigned short min_procs;
25703 @@ -119,44 +121,44 @@
25706 * kick the process from the list if it was not
25707 - * used for idle_timeout until min_procs is
25708 + * used for idle_timeout until min_procs is
25709 * reached. this helps to get the processlist
25710 * small again we had a small peak load.
25715 unsigned short idle_timeout;
25719 * time after a disabled remote connection is tried to be re-enabled
25727 unsigned short disable_time;
25730 * same fastcgi processes get a little bit larger
25731 - * than wanted. max_requests_per_proc kills a
25732 + * than wanted. max_requests_per_proc kills a
25733 * process after a number of handled requests.
25736 size_t max_requests_per_proc;
25747 - * if host is one of the local IP adresses the
25748 + * if host is one of the local IP adresses the
25749 * whole connection is local
25751 * if tcp/ip should be used host AND port have
25752 - * to be specified
25756 + * to be specified
25760 unsigned short port;
25763 @@ -169,7 +171,7 @@
25765 buffer *unixsocket;
25767 - /* if socket is local we can start the fastcgi
25768 + /* if socket is local we can start the fastcgi
25771 * bin-path is the path to the binary
25772 @@ -177,19 +179,19 @@
25773 * check min_procs and max_procs for the number
25774 * of process to start-up
25776 - buffer *bin_path;
25778 - /* bin-path is set bin-environment is taken to
25779 + buffer *bin_path;
25781 + /* bin-path is set bin-environment is taken to
25782 * create the environement before starting the
25790 array *bin_env_copy;
25794 - * docroot-translation between URL->phys and the
25795 + * docroot-translation between URL->phys and the
25799 @@ -208,7 +210,7 @@
25800 unsigned short mode;
25803 - * check_local tell you if the phys file is stat()ed
25804 + * check_local tell you if the phys file is stat()ed
25805 * or not. FastCGI doesn't care if the service is
25806 * remote. If the web-server side doesn't contain
25807 * the fastcgi-files we should not stat() for them
25808 @@ -218,11 +220,11 @@
25811 * append PATH_INFO to SCRIPT_FILENAME
25814 * php needs this if cgi.fix_pathinfo is provied
25820 unsigned short break_scriptfilename_for_php;
25823 @@ -231,12 +233,12 @@
25826 unsigned short allow_xsendfile;
25829 ssize_t load; /* replace by host->load */
25831 size_t max_id; /* corresponds most of the time to
25835 only if a process is killed max_id waits for the process itself
25836 to die and decrements its afterwards */
25838 @@ -245,17 +247,17 @@
25841 * one extension can have multiple hosts assigned
25842 - * one host can spawn additional processes on the same
25843 + * one host can spawn additional processes on the same
25844 * socket (if we control it)
25846 * ext -> host -> procs
25849 - * if the fastcgi process is remote that whole goes down
25850 + * if the fastcgi process is remote that whole goes down
25853 * ext -> host -> procs
25857 * in case of PHP and FCGI_CHILDREN we have again a procs
25858 * but we don't control it directly.
25859 @@ -268,7 +270,7 @@
25862 fcgi_extension_host **hosts;
25868 @@ -282,10 +284,10 @@
25875 array *ext_mapping;
25881 @@ -297,7 +299,7 @@
25890 @@ -306,55 +308,54 @@
25893 buffer_uint fcgi_request_id;
25900 - buffer *parse_response;
25907 plugin_config **config_storage;
25910 plugin_config conf; /* this is only used as long as no handler_ctx is setup */
25913 /* connection specific data */
25918 - FCGI_STATE_CONNECT_DELAYED,
25919 - FCGI_STATE_PREPARE_WRITE,
25920 - FCGI_STATE_WRITE,
25923 + FCGI_STATE_CONNECT_DELAYED,
25924 + FCGI_STATE_PREPARE_WRITE,
25925 + FCGI_STATE_WRITE,
25927 } fcgi_connection_state_t;
25931 fcgi_extension_host *host;
25932 fcgi_extension *ext;
25935 fcgi_connection_state_t state;
25936 time_t state_timestamp;
25939 int reconnects; /* number of reconnect attempts */
25941 - chunkqueue *rb; /* read queue */
25943 + chunkqueue *rb; /* the raw fcgi read-queue */
25944 + chunkqueue *http_rb; /* the decoded read-queue for http-parsing */
25945 chunkqueue *wb; /* write queue */
25947 - buffer *response_header;
25951 - int fd; /* fd to the fastcgi process */
25952 - int fde_ndx; /* index into the fd-event buffer */
25958 int send_content_body;
25961 plugin_config conf;
25964 connection *remote_conn; /* dumb pointer */
25965 plugin_data *plugin_data; /* dumb pointer */
25967 @@ -363,49 +364,6 @@
25968 /* ok, we need a prototype */
25969 static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents);
25971 -data_integer *status_counter_get_counter(server *srv, const char *s, size_t len) {
25972 - data_integer *di;
25974 - if (NULL == (di = (data_integer *)array_get_element(srv->status, s))) {
25975 - /* not found, create it */
25977 - if (NULL == (di = (data_integer *)array_get_unused_element(srv->status, TYPE_INTEGER))) {
25978 - di = data_integer_init();
25980 - buffer_copy_string_len(di->key, s, len);
25983 - array_insert_unique(srv->status, (data_unset *)di);
25988 -/* dummies of the statistic framework functions
25989 - * they will be moved to a statistics.c later */
25990 -int status_counter_inc(server *srv, const char *s, size_t len) {
25991 - data_integer *di = status_counter_get_counter(srv, s, len);
25998 -int status_counter_dec(server *srv, const char *s, size_t len) {
25999 - data_integer *di = status_counter_get_counter(srv, s, len);
26001 - if (di->value > 0) di->value--;
26006 -int status_counter_set(server *srv, const char *s, size_t len, int val) {
26007 - data_integer *di = status_counter_get_counter(srv, s, len);
26014 int fastcgi_status_copy_procname(buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
26015 buffer_copy_string(b, "fastcgi.backend.");
26016 buffer_append_string_buffer(b, host->id);
26017 @@ -421,7 +379,7 @@
26019 fastcgi_status_copy_procname(b, host, proc); \
26020 buffer_append_string(b, x); \
26021 - status_counter_set(srv, CONST_BUF_LEN(b), 0);
26022 + status_counter_set(CONST_BUF_LEN(b), 0);
26024 CLEAN(".disabled");
26026 @@ -429,42 +387,39 @@
26027 CLEAN(".connected");
26034 fastcgi_status_copy_procname(b, host, NULL); \
26035 buffer_append_string(b, x); \
26036 - status_counter_set(srv, CONST_BUF_LEN(b), 0);
26037 + status_counter_set(CONST_BUF_LEN(b), 0);
26047 static handler_ctx * handler_ctx_init() {
26048 handler_ctx * hctx;
26051 hctx = calloc(1, sizeof(*hctx));
26054 - hctx->fde_ndx = -1;
26056 - hctx->response_header = buffer_init();
26059 hctx->request_id = 0;
26060 hctx->state = FCGI_STATE_INIT;
26066 + hctx->sock = iosocket_init();
26068 hctx->reconnects = 0;
26069 hctx->send_content_body = 1;
26071 hctx->rb = chunkqueue_init();
26072 + hctx->http_rb = chunkqueue_init();
26073 hctx->wb = chunkqueue_init();
26079 @@ -473,12 +428,13 @@
26080 hctx->host->load--;
26084 - buffer_free(hctx->response_header);
26086 chunkqueue_free(hctx->rb);
26087 + chunkqueue_free(hctx->http_rb);
26088 chunkqueue_free(hctx->wb);
26090 + iosocket_free(hctx->sock);
26095 @@ -488,21 +444,21 @@
26096 f = calloc(1, sizeof(*f));
26097 f->unixsocket = buffer_init();
26098 f->connection_name = buffer_init();
26108 void fastcgi_process_free(fcgi_proc *f) {
26112 fastcgi_process_free(f->next);
26115 buffer_free(f->unixsocket);
26116 buffer_free(f->connection_name);
26122 @@ -519,13 +475,13 @@
26123 f->bin_env = array_init();
26124 f->bin_env_copy = array_init();
26125 f->strip_request_uri = buffer_init();
26131 void fastcgi_host_free(fcgi_extension_host *h) {
26135 buffer_free(h->id);
26136 buffer_free(h->host);
26137 buffer_free(h->unixsocket);
26138 @@ -534,49 +490,49 @@
26139 buffer_free(h->strip_request_uri);
26140 array_free(h->bin_env);
26141 array_free(h->bin_env_copy);
26144 fastcgi_process_free(h->first);
26145 fastcgi_process_free(h->unused_procs);
26153 fcgi_exts *fastcgi_extensions_init() {
26156 f = calloc(1, sizeof(*f));
26162 void fastcgi_extensions_free(fcgi_exts *f) {
26169 for (i = 0; i < f->used; i++) {
26170 fcgi_extension *fe;
26177 for (j = 0; j < fe->used; j++) {
26178 fcgi_extension_host *h;
26184 fastcgi_host_free(h);
26188 buffer_free(fe->key);
26202 @@ -625,24 +581,25 @@
26206 - fe->hosts[fe->used++] = fh;
26207 + fe->hosts[fe->used++] = fh;
26214 INIT_FUNC(mod_fastcgi_init) {
26218 p = calloc(1, sizeof(*p));
26221 p->fcgi_env = buffer_init();
26224 p->path = buffer_init();
26225 - p->parse_response = buffer_init();
26227 + p->resp = http_response_init();
26229 p->statuskey = buffer_init();
26235 @@ -650,81 +607,82 @@
26236 FREE_FUNC(mod_fastcgi_free) {
26237 plugin_data *p = p_d;
26238 buffer_uint *r = &(p->fcgi_request_id);
26243 if (r->ptr) free(r->ptr);
26246 buffer_free(p->fcgi_env);
26247 buffer_free(p->path);
26248 - buffer_free(p->parse_response);
26249 buffer_free(p->statuskey);
26252 + http_response_free(p->resp);
26254 if (p->config_storage) {
26256 for (i = 0; i < srv->config_context->used; i++) {
26257 plugin_config *s = p->config_storage[i];
26266 for (j = 0; j < exts->used; j++) {
26267 fcgi_extension *ex;
26270 ex = exts->exts[j];
26273 for (n = 0; n < ex->used; n++) {
26275 fcgi_extension_host *host;
26278 host = ex->hosts[n];
26281 for (proc = host->first; proc; proc = proc->next) {
26282 if (proc->pid != 0) kill(proc->pid, SIGTERM);
26284 - if (proc->is_local &&
26286 + if (proc->is_local &&
26287 !buffer_is_empty(proc->unixsocket)) {
26288 unlink(proc->unixsocket->ptr);
26293 for (proc = host->unused_procs; proc; proc = proc->next) {
26294 if (proc->pid != 0) kill(proc->pid, SIGTERM);
26296 - if (proc->is_local &&
26298 + if (proc->is_local &&
26299 !buffer_is_empty(proc->unixsocket)) {
26300 unlink(proc->unixsocket->ptr);
26307 fastcgi_extensions_free(s->exts);
26308 array_free(s->ext_mapping);
26313 free(p->config_storage);
26320 return HANDLER_GO_ON;
26323 static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
26327 if (!key || !val) return -1;
26330 dst = malloc(key_len + val_len + 3);
26331 memcpy(dst, key, key_len);
26332 dst[key_len] = '=';
26333 /* add the \0 from the value */
26334 memcpy(dst + key_len + 1, val, val_len + 1);
26337 if (env->size == 0) {
26339 env->ptr = malloc(env->size * sizeof(*env->ptr));
26340 @@ -732,9 +690,9 @@
26342 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
26346 env->ptr[env->used++] = dst;
26352 @@ -753,15 +711,15 @@
26353 if (env->size == 0) {
26355 env->ptr = malloc(env->size * sizeof(*env->ptr));
26356 - } else if (env->size == env->used) {
26357 + } else if (env->size == env->used) {
26359 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
26365 env->ptr[env->used++] = start;
26368 start = b->ptr + i + 1;
26371 @@ -794,7 +752,7 @@
26375 -static int fcgi_spawn_connection(server *srv,
26376 +static int fcgi_spawn_connection(server *srv,
26378 fcgi_extension_host *host,
26380 @@ -806,31 +764,27 @@
26382 struct sockaddr_in fcgi_addr_in;
26383 struct sockaddr *fcgi_addr;
26394 if (p->conf.debug) {
26395 log_error_write(srv, __FILE__, __LINE__, "sdb",
26396 "new proc, socket:", proc->port, proc->unixsocket);
26400 if (!buffer_is_empty(proc->unixsocket)) {
26401 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
26404 #ifdef HAVE_SYS_UN_H
26405 fcgi_addr_un.sun_family = AF_UNIX;
26406 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
26410 servlen = SUN_LEN(&fcgi_addr_un);
26412 - /* stevens says: */
26413 - servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
26416 socket_type = AF_UNIX;
26417 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
26419 @@ -844,108 +798,108 @@
26422 fcgi_addr_in.sin_family = AF_INET;
26425 if (buffer_is_empty(host->host)) {
26426 fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
26428 struct hostent *he;
26431 /* set a usefull default */
26432 fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
26437 if (NULL == (he = gethostbyname(host->host->ptr))) {
26438 - log_error_write(srv, __FILE__, __LINE__,
26439 - "sdb", "gethostbyname failed: ",
26440 + log_error_write(srv, __FILE__, __LINE__,
26441 + "sdb", "gethostbyname failed: ",
26442 h_errno, host->host);
26447 if (he->h_addrtype != AF_INET) {
26448 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
26453 if (he->h_length != sizeof(struct in_addr)) {
26454 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
26459 memcpy(&(fcgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
26463 fcgi_addr_in.sin_port = htons(proc->port);
26464 servlen = sizeof(fcgi_addr_in);
26467 socket_type = AF_INET;
26468 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
26471 buffer_copy_string(proc->connection_name, "tcp:");
26472 buffer_append_string_buffer(proc->connection_name, host->host);
26473 buffer_append_string(proc->connection_name, ":");
26474 buffer_append_long(proc->connection_name, proc->port);
26478 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
26479 - log_error_write(srv, __FILE__, __LINE__, "ss",
26480 + log_error_write(srv, __FILE__, __LINE__, "ss",
26481 "failed:", strerror(errno));
26486 if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
26487 /* server is not up, spawn in */
26491 - if (errno != ENOENT &&
26493 + if (errno != ENOENT &&
26494 !buffer_is_empty(proc->unixsocket)) {
26495 unlink(proc->unixsocket->ptr);
26502 /* reopen socket */
26503 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
26504 - log_error_write(srv, __FILE__, __LINE__, "ss",
26505 + log_error_write(srv, __FILE__, __LINE__, "ss",
26506 "socket failed:", strerror(errno));
26512 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
26513 - log_error_write(srv, __FILE__, __LINE__, "ss",
26514 + log_error_write(srv, __FILE__, __LINE__, "ss",
26515 "socketsockopt failed:", strerror(errno));
26520 /* create socket */
26521 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
26522 - log_error_write(srv, __FILE__, __LINE__, "sbs",
26523 - "bind failed for:",
26524 + log_error_write(srv, __FILE__, __LINE__, "sbs",
26525 + "bind failed for:",
26526 proc->connection_name,
26532 if (-1 == listen(fcgi_fd, 1024)) {
26533 - log_error_write(srv, __FILE__, __LINE__, "ss",
26534 + log_error_write(srv, __FILE__, __LINE__, "ss",
26535 "listen failed:", strerror(errno));
26542 switch ((child = fork())) {
26550 /* create environment */
26559 @@ -955,18 +909,18 @@
26560 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
26565 /* we don't need the client socket */
26566 for (i = 3; i < 256; i++) {
26571 /* build clean environment */
26572 if (host->bin_env_copy->used) {
26573 for (i = 0; i < host->bin_env_copy->used; i++) {
26574 data_string *ds = (data_string *)host->bin_env_copy->data[i];
26578 if (NULL != (ge = getenv(ds->value->ptr))) {
26579 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
26581 @@ -974,39 +928,39 @@
26583 for (i = 0; environ[i]; i++) {
26587 if (NULL != (eq = strchr(environ[i], '='))) {
26588 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
26594 /* create environment */
26595 for (i = 0; i < host->bin_env->used; i++) {
26596 data_string *ds = (data_string *)host->bin_env->data[i];
26599 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
26603 for (i = 0; i < env.used; i++) {
26604 /* search for PHP_FCGI_CHILDREN */
26605 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
26609 /* not found, add a default */
26610 if (i == env.used) {
26611 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
26615 env.ptr[env.used] = NULL;
26617 parse_binpath(&arg, host->bin_path);
26620 /* chdir into the base of the bin-path,
26621 * search for the last / */
26622 if (NULL != (c = strrchr(arg.ptr[0], '/'))) {
26626 /* change to the physical directory */
26627 if (-1 == chdir(arg.ptr[0])) {
26629 @@ -1018,12 +972,12 @@
26632 execve(arg.ptr[0], arg.ptr, env.ptr);
26634 - log_error_write(srv, __FILE__, __LINE__, "sbs",
26636 + log_error_write(srv, __FILE__, __LINE__, "sbs",
26637 "execve failed for:", host->bin_path, strerror(errno));
26646 @@ -1031,17 +985,17 @@
26653 select(0, NULL, NULL, NULL, &tv);
26656 switch (waitpid(child, &status, WNOHANG)) {
26658 /* child still running after timeout, good */
26661 /* no PID found ? should never happen */
26662 - log_error_write(srv, __FILE__, __LINE__, "ss",
26663 + log_error_write(srv, __FILE__, __LINE__, "ss",
26664 "pid not found:", strerror(errno));
26667 @@ -1049,10 +1003,10 @@
26668 "the fastcgi-backend", host->bin_path, "failed to start:");
26669 /* the child should not terminate at all */
26670 if (WIFEXITED(status)) {
26671 - log_error_write(srv, __FILE__, __LINE__, "sdb",
26672 - "child exited with status",
26673 + log_error_write(srv, __FILE__, __LINE__, "sdb",
26674 + "child exited with status",
26675 WEXITSTATUS(status), host->bin_path);
26676 - log_error_write(srv, __FILE__, __LINE__, "s",
26677 + log_error_write(srv, __FILE__, __LINE__, "s",
26678 "if you try do run PHP as FastCGI backend make sure you use the FastCGI enabled version.\n"
26679 "You can find out if it is the right one by executing 'php -v' and it should display '(cgi-fcgi)' "
26680 "in the output, NOT (cgi) NOR (cli)\n"
26681 @@ -1060,8 +1014,8 @@
26682 log_error_write(srv, __FILE__, __LINE__, "s",
26683 "If this is PHP on Gentoo add fastcgi to the USE flags");
26684 } else if (WIFSIGNALED(status)) {
26685 - log_error_write(srv, __FILE__, __LINE__, "sd",
26686 - "terminated by signal:",
26687 + log_error_write(srv, __FILE__, __LINE__, "sd",
26688 + "terminated by signal:",
26691 if (WTERMSIG(status) == 11) {
26692 @@ -1071,8 +1025,8 @@
26693 "If this is PHP try to remove the byte-code caches for now and try again.");
26696 - log_error_write(srv, __FILE__, __LINE__, "sd",
26697 - "child died somehow:",
26698 + log_error_write(srv, __FILE__, __LINE__, "sd",
26699 + "child died somehow:",
26703 @@ -1082,26 +1036,26 @@
26705 proc->last_used = srv->cur_ts;
26706 proc->is_local = 1;
26713 proc->is_local = 0;
26717 if (p->conf.debug) {
26718 log_error_write(srv, __FILE__, __LINE__, "sb",
26719 "(debug) socket is already used, won't spawn:",
26720 proc->connection_name);
26725 proc->state = PROC_STATE_RUNNING;
26726 host->active_procs++;
26735 @@ -1111,93 +1065,93 @@
26738 buffer *fcgi_mode = buffer_init();
26740 - config_values_t cv[] = {
26742 + config_values_t cv[] = {
26743 { "fastcgi.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
26744 { "fastcgi.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
26745 { "fastcgi.map-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
26746 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26750 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26753 for (i = 0; i < srv->config_context->used; i++) {
26758 s = malloc(sizeof(plugin_config));
26759 s->exts = fastcgi_extensions_init();
26761 s->ext_mapping = array_init();
26764 cv[0].destination = s->exts;
26765 cv[1].destination = &(s->debug);
26766 cv[2].destination = s->ext_mapping;
26769 p->config_storage[i] = s;
26770 ca = ((data_config *)srv->config_context->data[i])->value;
26773 if (0 != config_insert_values_global(srv, ca, cv)) {
26774 return HANDLER_ERROR;
26784 if (NULL != (du = array_get_element(ca, "fastcgi.server"))) {
26786 data_array *da = (data_array *)du;
26789 if (du->type != TYPE_ARRAY) {
26790 - log_error_write(srv, __FILE__, __LINE__, "sss",
26791 + log_error_write(srv, __FILE__, __LINE__, "sss",
26792 "unexpected type for key: ", "fastcgi.server", "array of strings");
26795 return HANDLER_ERROR;
26800 - * fastcgi.server = ( "<ext>" => ( ... ),
26804 + * fastcgi.server = ( "<ext>" => ( ... ),
26805 * "<ext>" => ( ... ) )
26809 for (j = 0; j < da->value->used; j++) {
26811 data_array *da_ext = (data_array *)da->value->data[j];
26814 if (da->value->data[j]->type != TYPE_ARRAY) {
26815 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
26816 - "unexpected type for key: ", "fastcgi.server",
26817 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
26818 + "unexpected type for key: ", "fastcgi.server",
26819 "[", da->value->data[j]->key, "](string)");
26822 return HANDLER_ERROR;
26826 - * da_ext->key == name of the extension
26829 + * da_ext->key == name of the extension
26833 - * fastcgi.server = ( "<ext>" =>
26834 - * ( "<host>" => ( ... ),
26837 + * fastcgi.server = ( "<ext>" =>
26838 + * ( "<host>" => ( ... ),
26839 * "<host>" => ( ... )
26846 for (n = 0; n < da_ext->value->used; n++) {
26847 data_array *da_host = (data_array *)da_ext->value->data[n];
26850 fcgi_extension_host *host;
26852 - config_values_t fcv[] = {
26854 + config_values_t fcv[] = {
26855 { "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
26856 { "docroot", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
26857 { "mode", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
26858 { "socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
26859 { "bin-path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
26862 { "check-local", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
26863 { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
26864 { "min-procs-not-working", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 this is broken for now */
26865 @@ -1205,28 +1159,28 @@
26866 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
26867 { "idle-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
26868 { "disable-time", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
26871 { "bin-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
26872 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
26875 { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
26876 { "allow-x-send-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */
26877 { "strip-request-uri", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 16 */
26880 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26884 if (da_host->type != TYPE_ARRAY) {
26885 - log_error_write(srv, __FILE__, __LINE__, "ssSBS",
26886 - "unexpected type for key:",
26887 - "fastcgi.server",
26888 + log_error_write(srv, __FILE__, __LINE__, "ssSBS",
26889 + "unexpected type for key:",
26890 + "fastcgi.server",
26891 "[", da_host->key, "](string)");
26894 return HANDLER_ERROR;
26898 host = fastcgi_host_init();
26901 buffer_copy_string_buffer(host->id, da_host->key);
26903 host->check_local = 1;
26904 @@ -1238,13 +1192,13 @@
26905 host->disable_time = 60;
26906 host->break_scriptfilename_for_php = 0;
26907 host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
26910 fcv[0].destination = host->host;
26911 fcv[1].destination = host->docroot;
26912 fcv[2].destination = fcgi_mode;
26913 fcv[3].destination = host->unixsocket;
26914 fcv[4].destination = host->bin_path;
26917 fcv[5].destination = &(host->check_local);
26918 fcv[6].destination = &(host->port);
26919 fcv[7].destination = &(host->min_procs);
26920 @@ -1252,35 +1206,35 @@
26921 fcv[9].destination = &(host->max_load_per_proc);
26922 fcv[10].destination = &(host->idle_timeout);
26923 fcv[11].destination = &(host->disable_time);
26926 fcv[12].destination = host->bin_env;
26927 fcv[13].destination = host->bin_env_copy;
26928 fcv[14].destination = &(host->break_scriptfilename_for_php);
26929 fcv[15].destination = &(host->allow_xsendfile);
26930 fcv[16].destination = host->strip_request_uri;
26933 if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
26934 return HANDLER_ERROR;
26937 - if ((!buffer_is_empty(host->host) || host->port) &&
26939 + if ((!buffer_is_empty(host->host) || host->port) &&
26940 !buffer_is_empty(host->unixsocket)) {
26941 - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
26942 + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
26943 "either host/port or socket have to be set in:",
26946 da_ext->key, " => (",
26947 da_host->key, " ( ...");
26949 return HANDLER_ERROR;
26953 if (!buffer_is_empty(host->unixsocket)) {
26954 /* unix domain socket */
26957 if (host->unixsocket->used > UNIX_PATH_MAX - 2) {
26958 - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
26959 + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
26960 "unixsocket is too long in:",
26963 da_ext->key, " => (",
26964 da_host->key, " ( ...");
26966 @@ -1288,37 +1242,37 @@
26971 - if (buffer_is_empty(host->host) &&
26973 + if (buffer_is_empty(host->host) &&
26974 buffer_is_empty(host->bin_path)) {
26975 - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
26976 + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
26977 "host or binpath have to be set in:",
26980 da_ext->key, " => (",
26981 da_host->key, " ( ...");
26984 return HANDLER_ERROR;
26985 } else if (host->port == 0) {
26986 - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
26987 + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
26988 "port has to be set in:",
26991 da_ext->key, " => (",
26992 da_host->key, " ( ...");
26994 return HANDLER_ERROR;
26998 - if (!buffer_is_empty(host->bin_path)) {
27000 + if (!buffer_is_empty(host->bin_path)) {
27001 /* a local socket + self spawning */
27004 /* HACK: just to make sure the adaptive spawing is disabled */
27005 host->min_procs = host->max_procs;
27008 if (host->min_procs > host->max_procs) host->max_procs = host->min_procs;
27009 if (host->max_load_per_proc < 1) host->max_load_per_proc = 0;
27013 log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
27014 "--- fastcgi spawning local",
27015 @@ -1328,7 +1282,7 @@
27016 "\n\tmin-procs:", host->min_procs,
27017 "\n\tmax-procs:", host->max_procs);
27021 for (pno = 0; pno < host->min_procs; pno++) {
27024 @@ -1343,7 +1297,7 @@
27025 buffer_append_string(proc->unixsocket, "-");
27026 buffer_append_long(proc->unixsocket, pno);
27031 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
27032 "--- fastcgi spawning",
27033 @@ -1351,7 +1305,7 @@
27034 "\n\tsocket", host->unixsocket,
27035 "\n\tcurrent:", pno, "/", host->min_procs);
27039 if (fcgi_spawn_connection(srv, p, host, proc)) {
27040 log_error_write(srv, __FILE__, __LINE__, "s",
27041 "[ERROR]: spawning fcgi failed.");
27042 @@ -1359,35 +1313,35 @@
27045 fastcgi_status_init(srv, p->statuskey, host, proc);
27048 proc->next = host->first;
27049 if (host->first) host->first->prev = proc;
27052 host->first = proc;
27058 proc = fastcgi_process_init();
27059 proc->id = host->num_procs++;
27061 host->active_procs++;
27062 proc->state = PROC_STATE_RUNNING;
27065 if (buffer_is_empty(host->unixsocket)) {
27066 proc->port = host->port;
27068 buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
27072 fastcgi_status_init(srv, p->statuskey, host, proc);
27074 host->first = proc;
27077 host->min_procs = 1;
27078 host->max_procs = 1;
27082 if (!buffer_is_empty(fcgi_mode)) {
27083 if (strcmp(fcgi_mode->ptr, "responder") == 0) {
27084 host->mode = FCGI_RESPONDER;
27085 @@ -1411,16 +1365,16 @@
27091 buffer_free(fcgi_mode);
27094 return HANDLER_GO_ON;
27097 static int fcgi_set_state(server *srv, handler_ctx *hctx, fcgi_connection_state_t state) {
27098 hctx->state = state;
27099 hctx->state_timestamp = srv->cur_ts;
27105 @@ -1429,13 +1383,13 @@
27108 buffer_uint *r = &(p->fcgi_request_id);
27113 for (i = 0; i < r->used; i++) {
27114 if (r->ptr[i] > m) m = r->ptr[i];
27118 if (r->size == 0) {
27120 r->ptr = malloc(sizeof(*r->ptr) * r->size);
27121 @@ -1443,54 +1397,55 @@
27123 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
27127 r->ptr[r->used++] = ++m;
27133 static int fcgi_requestid_del(server *srv, plugin_data *p, size_t request_id) {
27135 buffer_uint *r = &(p->fcgi_request_id);
27140 for (i = 0; i < r->used; i++) {
27141 if (r->ptr[i] == request_id) break;
27145 if (i != r->used) {
27149 if (i != r->used - 1) {
27150 r->ptr[i] = r->ptr[r->used - 1];
27158 void fcgi_connection_close(server *srv, handler_ctx *hctx) {
27163 if (NULL == hctx) return;
27166 p = hctx->plugin_data;
27167 con = hctx->remote_conn;
27170 if (con->mode != p->id) {
27175 - if (hctx->fd != -1) {
27176 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
27177 - fdevent_unregister(srv->ev, hctx->fd);
27180 + if (hctx->sock->fd != -1) {
27181 + fdevent_event_del(srv->ev, hctx->sock);
27182 + fdevent_unregister(srv->ev, hctx->sock);
27183 + closesocket(hctx->sock->fd);
27184 + hctx->sock->fd = -1;
27190 if (hctx->request_id != 0) {
27191 fcgi_requestid_del(srv, p, hctx->request_id);
27193 @@ -1499,111 +1454,111 @@
27194 if (hctx->got_proc) {
27195 /* after the connect the process gets a load */
27196 hctx->proc->load--;
27198 - status_counter_dec(srv, CONST_STR_LEN("fastcgi.active-requests"));
27200 + status_counter_dec(CONST_STR_LEN("fastcgi.active-requests"));
27202 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
27203 buffer_append_string(p->statuskey, ".load");
27205 - status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
27206 + status_counter_set(CONST_BUF_LEN(p->statuskey), hctx->proc->load);
27208 if (p->conf.debug) {
27209 log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
27210 - "released proc:",
27211 - "pid:", hctx->proc->pid,
27212 - "socket:", hctx->proc->connection_name,
27213 + "released proc:",
27214 + "pid:", hctx->proc->pid,
27215 + "socket:", hctx->proc->connection_name,
27216 "load:", hctx->proc->load);
27223 handler_ctx_free(hctx);
27224 - con->plugin_ctx[p->id] = NULL;
27225 + con->plugin_ctx[p->id] = NULL;
27228 static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
27229 plugin_data *p = hctx->plugin_data;
27240 * connect was ok, connection was accepted
27241 * but the php accept loop checks after the accept if it should die or not.
27243 - * if yes we can only detect it at a write()
27246 + * if yes we can only detect it at a write()
27248 * next step is resetting this attemp and setup a connection again
27251 * if we have more then 5 reconnects for the same request, die
27258 * we have a connection but the child died by some other reason
27263 - if (hctx->fd != -1) {
27264 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
27265 - fdevent_unregister(srv->ev, hctx->fd);
27267 + if (hctx->sock->fd != -1) {
27268 + fdevent_event_del(srv->ev, hctx->sock);
27269 + fdevent_unregister(srv->ev, hctx->sock);
27270 + close(hctx->sock->fd);
27273 + hctx->sock->fd = -1;
27277 fcgi_requestid_del(srv, p, hctx->request_id);
27280 fcgi_set_state(srv, hctx, FCGI_STATE_INIT);
27283 hctx->request_id = 0;
27284 hctx->reconnects++;
27287 if (p->conf.debug > 2) {
27289 log_error_write(srv, __FILE__, __LINE__, "sdb",
27290 - "release proc for reconnect:",
27291 + "release proc for reconnect:",
27292 hctx->proc->pid, hctx->proc->connection_name);
27294 log_error_write(srv, __FILE__, __LINE__, "sb",
27295 - "release proc for reconnect:",
27296 + "release proc for reconnect:",
27297 hctx->host->unixsocket);
27301 - if (hctx->proc && hctx->got_proc) {
27302 + if (hctx->proc && hctx->got_proc) {
27303 hctx->proc->load--;
27306 /* perhaps another host gives us more luck */
27307 hctx->host->load--;
27315 static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) {
27316 plugin_data *p = p_d;
27319 fcgi_connection_close(srv, con->plugin_ctx[p->id]);
27322 return HANDLER_GO_ON;
27326 static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
27330 if (!key || !val) return -1;
27333 len = key_len + val_len;
27336 len += key_len > 127 ? 4 : 1;
27337 len += val_len > 127 ? 4 : 1;
27340 buffer_prepare_append(env, len);
27343 if (key_len > 127) {
27344 env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80;
27345 env->ptr[env->used++] = (key_len >> 16) & 0xff;
27346 @@ -1612,7 +1567,7 @@
27348 env->ptr[env->used++] = (key_len >> 0) & 0xff;
27352 if (val_len > 127) {
27353 env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80;
27354 env->ptr[env->used++] = (val_len >> 16) & 0xff;
27355 @@ -1621,12 +1576,12 @@
27357 env->ptr[env->used++] = (val_len >> 0) & 0xff;
27361 memcpy(env->ptr + env->used, key, key_len);
27362 env->used += key_len;
27363 memcpy(env->ptr + env->used, val, val_len);
27364 env->used += val_len;
27370 @@ -1639,11 +1594,11 @@
27371 header->contentLengthB1 = (contentLength >> 8) & 0xff;
27372 header->paddingLength = paddingLength;
27373 header->reserved = 0;
27384 @@ -1665,26 +1620,23 @@
27385 struct sockaddr_un fcgi_addr_un;
27390 fcgi_extension_host *host = hctx->host;
27391 fcgi_proc *proc = hctx->proc;
27392 - int fcgi_fd = hctx->fd;
27394 + int fcgi_fd = hctx->sock->fd;
27396 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
27399 if (!buffer_is_empty(proc->unixsocket)) {
27400 #ifdef HAVE_SYS_UN_H
27401 /* use the unix domain socket */
27402 fcgi_addr_un.sun_family = AF_UNIX;
27403 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
27406 servlen = SUN_LEN(&fcgi_addr_un);
27408 - /* stevens says: */
27409 - servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
27412 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
27415 if (buffer_is_empty(proc->connection_name)) {
27416 /* on remote spawing we have to set the connection-name now */
27417 buffer_copy_string(proc->connection_name, "unix:");
27418 @@ -1695,16 +1647,18 @@
27421 fcgi_addr_in.sin_family = AF_INET;
27423 if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) {
27424 - log_error_write(srv, __FILE__, __LINE__, "sbs",
27425 - "converting IP-adress failed for", host->host,
27426 + log_error_write(srv, __FILE__, __LINE__, "sbs",
27427 + "converting IP-adress failed for", host->host,
27428 "\nBe sure to specify an IP address here");
27434 fcgi_addr_in.sin_port = htons(proc->port);
27435 servlen = sizeof(fcgi_addr_in);
27438 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
27440 if (buffer_is_empty(proc->connection_name)) {
27441 @@ -1715,20 +1669,20 @@
27442 buffer_append_long(proc->connection_name, proc->port);
27447 if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
27448 - if (errno == EINPROGRESS ||
27449 + if (errno == EINPROGRESS ||
27450 errno == EALREADY ||
27452 if (hctx->conf.debug > 2) {
27453 - log_error_write(srv, __FILE__, __LINE__, "sb",
27454 + log_error_write(srv, __FILE__, __LINE__, "sb",
27455 "connect delayed, will continue later:", proc->connection_name);
27459 return CONNECTION_DELAYED;
27460 } else if (errno == EAGAIN) {
27461 if (hctx->conf.debug) {
27462 - log_error_write(srv, __FILE__, __LINE__, "sbsd",
27463 + log_error_write(srv, __FILE__, __LINE__, "sbsd",
27464 "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
27465 "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
27466 "The load for this fastcgi backend", proc->connection_name, "is", proc->load);
27467 @@ -1736,8 +1690,8 @@
27469 return CONNECTION_OVERLOADED;
27471 - log_error_write(srv, __FILE__, __LINE__, "sssb",
27472 - "connect failed:",
27473 + log_error_write(srv, __FILE__, __LINE__, "sssb",
27474 + "connect failed:",
27475 strerror(errno), "on",
27476 proc->connection_name);
27478 @@ -1747,7 +1701,7 @@
27480 hctx->reconnects = 0;
27481 if (hctx->conf.debug > 1) {
27482 - log_error_write(srv, __FILE__, __LINE__, "sd",
27483 + log_error_write(srv, __FILE__, __LINE__, "sd",
27484 "connect succeeded: ", fcgi_fd);
27487 @@ -1756,21 +1710,21 @@
27489 static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
27493 for (i = 0; i < con->request.headers->used; i++) {
27497 ds = (data_string *)con->request.headers->data[i];
27500 if (ds->value->used && ds->key->used) {
27502 buffer_reset(srv->tmp_buf);
27505 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
27506 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
27507 srv->tmp_buf->used--;
27511 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
27512 for (j = 0; j < ds->key->used - 1; j++) {
27514 @@ -1784,20 +1738,20 @@
27515 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
27517 srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
27520 fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
27525 for (i = 0; i < con->environment->used; i++) {
27529 ds = (data_string *)con->environment->data[i];
27532 if (ds->value->used && ds->key->used) {
27534 buffer_reset(srv->tmp_buf);
27537 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
27538 for (j = 0; j < ds->key->used - 1; j++) {
27540 @@ -1811,11 +1765,11 @@
27541 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
27543 srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
27546 fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
27554 @@ -1824,24 +1778,24 @@
27555 FCGI_BeginRequestRecord beginRecord;
27556 FCGI_Header header;
27563 char b2[INET6_ADDRSTRLEN + 1];
27567 plugin_data *p = hctx->plugin_data;
27568 fcgi_extension_host *host= hctx->host;
27570 connection *con = hctx->remote_conn;
27571 server_socket *srv_sock = con->srv_socket;
27574 sock_addr our_addr;
27575 socklen_t our_addr_len;
27578 /* send FCGI_BEGIN_REQUEST */
27581 fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, request_id, sizeof(beginRecord.body), 0);
27582 beginRecord.body.roleB0 = host->mode;
27583 beginRecord.body.roleB1 = 0;
27584 @@ -1849,21 +1803,21 @@
27585 memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
27587 b = chunkqueue_get_append_buffer(hctx->wb);
27590 buffer_copy_memory(b, (const char *)&beginRecord, sizeof(beginRecord));
27593 /* send FCGI_PARAMS */
27594 buffer_prepare_copy(p->fcgi_env, 1024);
27597 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
27600 if (con->server_name->used) {
27601 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
27604 - s = inet_ntop(srv_sock->addr.plain.sa_family,
27605 - srv_sock->addr.plain.sa_family == AF_INET6 ?
27606 + s = inet_ntop(srv_sock->addr.plain.sa_family,
27607 + srv_sock->addr.plain.sa_family == AF_INET6 ?
27608 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
27609 (const void *) &(srv_sock->addr.ipv4.sin_addr),
27611 @@ -1872,50 +1826,50 @@
27613 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
27617 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
27623 ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
27625 ntohs(srv_sock->addr.ipv4.sin_port)
27630 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
27633 /* get the server-side of the connection to the client */
27634 our_addr_len = sizeof(our_addr);
27636 - if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
27638 + if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
27639 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
27641 s = inet_ntop_cache_get_ip(srv, &(our_addr));
27643 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
27649 ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
27651 ntohs(con->dst_addr.ipv4.sin_port)
27656 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
27659 s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
27660 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
27663 if (!buffer_is_empty(con->authed_user)) {
27664 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_USER"),
27665 CONST_BUF_LEN(con->authed_user));
27669 if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) {
27670 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
27673 /* request.content_length < SSIZE_MAX, see request.c */
27674 ltostr(buf, con->request.content_length);
27675 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
27676 @@ -1930,12 +1884,12 @@
27679 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
27682 if (!buffer_is_empty(con->request.pathinfo)) {
27683 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
27686 /* PATH_TRANSLATED is only defined if PATH_INFO is set */
27689 if (!buffer_is_empty(host->docroot)) {
27690 buffer_copy_string_buffer(p->path, host->docroot);
27692 @@ -1957,27 +1911,27 @@
27695 if (!buffer_is_empty(host->docroot)) {
27697 - * rewrite SCRIPT_FILENAME
27700 + * rewrite SCRIPT_FILENAME
27705 buffer_copy_string_buffer(p->path, host->docroot);
27706 buffer_append_string_buffer(p->path, con->uri.path);
27709 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
27710 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
27712 buffer_copy_string_buffer(p->path, con->physical.path);
27714 - /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
27717 + /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
27719 * see src/sapi/cgi_main.c, init_request_info()
27721 if (host->break_scriptfilename_for_php) {
27722 buffer_append_string_buffer(p->path, con->request.pathinfo);
27726 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
27727 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
27729 @@ -1987,7 +1941,7 @@
27733 - * stripping /app1 or /app1/ should lead to
27734 + * stripping /app1 or /app1/ should lead to
27738 @@ -2001,7 +1955,7 @@
27739 0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, host->strip_request_uri->used - 1)) {
27740 /* the left is the same */
27742 - fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
27743 + fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
27744 con->request.orig_uri->ptr + (host->strip_request_uri->used - 2),
27745 con->request.orig_uri->used - (host->strip_request_uri->used - 2));
27747 @@ -2018,26 +1972,26 @@
27749 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
27753 s = get_http_method_name(con->request.http_method);
27754 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
27755 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
27756 s = get_http_version_name(con->request.http_version);
27757 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
27761 if (srv_sock->is_ssl) {
27762 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
27769 fcgi_env_add_request_headers(srv, con, p);
27772 fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0);
27773 buffer_append_memory(b, (const char *)&header, sizeof(header));
27774 buffer_append_memory(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used);
27777 fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
27778 buffer_append_memory(b, (const char *)&header, sizeof(header));
27780 @@ -2045,7 +1999,7 @@
27781 hctx->wb->bytes_in += b->used - 1;
27783 if (con->request.content_length) {
27784 - chunkqueue *req_cq = con->request_content_queue;
27785 + chunkqueue *req_cq = con->recv;
27789 @@ -2057,7 +2011,7 @@
27791 /* we announce toWrite octects
27792 * now take all the request_content chunk that we need to fill this request
27796 b = chunkqueue_get_append_buffer(hctx->wb);
27797 fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0);
27798 @@ -2080,16 +2034,16 @@
27799 if (weHave > weWant - written) weHave = weWant - written;
27801 if (p->conf.debug > 10) {
27802 - fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n",
27803 - __FILE__, __LINE__,
27806 - req_c->file.length,
27807 + fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n",
27808 + __FILE__, __LINE__,
27811 + req_c->file.length,
27812 req_c->file.name->ptr);
27815 assert(weHave != 0);
27818 chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
27820 req_c->offset += weHave;
27821 @@ -2104,7 +2058,7 @@
27822 * - we reference the tempfile from the request-content-queue several times
27823 * if the req_c is larger than FCGI_MAX_LENGTH
27824 * - we can't simply cleanup the request-content-queue as soon as possible
27825 - * as it would remove the tempfiles
27826 + * as it would remove the tempfiles
27827 * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last
27828 * referencing chunk of the fastcgi-write-queue
27830 @@ -2141,7 +2095,7 @@
27831 req_c->offset += weHave;
27832 req_cq->bytes_out += weHave;
27836 hctx->wb->bytes_in += weHave;
27838 if (req_c->offset == req_c->mem->used - 1) {
27839 @@ -2155,12 +2109,12 @@
27845 b->used++; /* add virtual \0 */
27851 b = chunkqueue_get_append_buffer(hctx->wb);
27852 /* terminate STDIN */
27853 fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0);
27854 @@ -2175,118 +2129,19 @@
27855 if ((i+1) % 16 == 0) {
27857 for (j = i-15; j <= i; j++) {
27858 - fprintf(stderr, "%c",
27859 + fprintf(stderr, "%c",
27860 isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
27862 fprintf(stderr, "\n");
27870 -static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
27873 - handler_ctx *hctx = con->plugin_ctx[p->id];
27874 - fcgi_extension_host *host= hctx->host;
27878 - buffer_copy_string_buffer(p->parse_response, in);
27880 - /* search for \n */
27881 - for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {
27882 - char *key, *value;
27886 - /* a good day. Someone has read the specs and is sending a \r\n to us */
27888 - if (ns > p->parse_response->ptr &&
27889 - *(ns-1) == '\r') {
27896 - if (NULL == (value = strchr(s, ':'))) {
27897 - /* we expect: "<key>: <value>\n" */
27901 - key_len = value - key;
27905 - while (*value == ' ' || *value == '\t') value++;
27907 - if (host->mode != FCGI_AUTHORIZER ||
27908 - !(con->http_status == 0 ||
27909 - con->http_status == 200)) {
27910 - /* authorizers shouldn't affect the response headers sent back to the client */
27912 - /* don't forward Status: */
27913 - if (0 != strncasecmp(key, "Status", key_len)) {
27914 - if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
27915 - ds = data_response_init();
27917 - buffer_copy_string_len(ds->key, key, key_len);
27918 - buffer_copy_string(ds->value, value);
27920 - array_insert_unique(con->response.headers, (data_unset *)ds);
27924 - switch(key_len) {
27926 - if (0 == strncasecmp(key, "Date", key_len)) {
27927 - con->parsed_response |= HTTP_DATE;
27931 - if (0 == strncasecmp(key, "Status", key_len)) {
27932 - con->http_status = strtol(value, NULL, 10);
27933 - con->parsed_response |= HTTP_STATUS;
27937 - if (0 == strncasecmp(key, "Location", key_len)) {
27938 - con->parsed_response |= HTTP_LOCATION;
27942 - if (0 == strncasecmp(key, "Connection", key_len)) {
27943 - con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
27944 - con->parsed_response |= HTTP_CONNECTION;
27948 - if (0 == strncasecmp(key, "Content-Length", key_len)) {
27949 - con->response.content_length = strtol(value, NULL, 10);
27950 - con->parsed_response |= HTTP_CONTENT_LENGTH;
27952 - if (con->response.content_length < 0) con->response.content_length = 0;
27960 - /* CGI/1.1 rev 03 - 7.2.1.2 */
27961 - if ((con->parsed_response & HTTP_LOCATION) &&
27962 - !(con->parsed_response & HTTP_STATUS)) {
27963 - con->http_status = 302;
27975 @@ -2327,9 +2182,9 @@
27979 - /* we have at least a header, now check how much me have to fetch */
27980 + /* we have at least a header, now check how much me have to fetch */
27981 header = (FCGI_Header *)(packet->b->ptr);
27984 packet->len = (header->contentLengthB0 | (header->contentLengthB1 << 8)) + header->paddingLength;
27985 packet->request_id = (header->requestIdB0 | (header->requestIdB1 << 8));
27986 packet->type = header->type;
27987 @@ -2348,7 +2203,7 @@
27988 size_t weHave = c->mem->used - c->offset - offset - 1;
27990 if (weHave > weWant) weHave = weWant;
27993 buffer_append_string_len(packet->b, c->mem->ptr + c->offset + offset, weHave);
27995 /* we only skipped the first 8 bytes as they are the fcgi header */
27996 @@ -2380,65 +2235,42 @@
27999 chunkqueue_remove_finished_chunks(hctx->rb);
28005 static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
28011 plugin_data *p = hctx->plugin_data;
28012 connection *con = hctx->remote_conn;
28013 - int fcgi_fd = hctx->fd;
28014 fcgi_extension_host *host= hctx->host;
28015 fcgi_proc *proc = hctx->proc;
28018 - * check how much we have to read
28020 - if (ioctl(hctx->fd, FIONREAD, &toread)) {
28021 - log_error_write(srv, __FILE__, __LINE__, "sd",
28022 - "unexpected end-of-file (perhaps the fastcgi process died):",
28027 - /* init read-buffer */
28029 - if (toread > 0) {
28032 - b = chunkqueue_get_append_buffer(hctx->rb);
28033 - buffer_prepare_copy(b, toread + 1);
28035 - /* append to read-buffer */
28036 - if (-1 == (r = read(hctx->fd, b->ptr, toread))) {
28037 - log_error_write(srv, __FILE__, __LINE__, "sds",
28038 - "unexpected end-of-file (perhaps the fastcgi process died):",
28039 - fcgi_fd, strerror(errno));
28043 - /* this should be catched by the b > 0 above */
28047 - b->used = r + 1; /* one extra for the fake \0 */
28048 - b->ptr[b->used - 1] = '\0';
28050 - log_error_write(srv, __FILE__, __LINE__, "ssdsb",
28051 - "unexpected end-of-file (perhaps the fastcgi process died):",
28052 - "pid:", proc->pid,
28053 - "socket:", proc->connection_name);
28055 + /* in case we read nothing, check the return code
28056 + * if we got something, be happy :)
28058 + * Ok, to be honest:
28059 + * - it is fine to receive a EAGAIN on a second read() call
28060 + * - it might be fine they we get a con-close on a second read() call */
28061 + switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
28062 + case NETWORK_STATUS_WAIT_FOR_EVENT:
28063 + /* a EAGAIN after we read exactly the chunk-size */
28065 + ERROR("%s", "oops, got a EAGAIN even if we just got call for the event, wired");
28067 + case NETWORK_STATUS_SUCCESS:
28070 + ERROR("reading from fastcgi socket failed (fd=%d)", hctx->sock->fd);
28075 * parse the fastcgi packets and forward the content to the write-queue
28080 fastcgi_response_packet packet;
28082 @@ -2454,132 +2286,165 @@
28084 /* is the header already finished */
28085 if (0 == con->file_started) {
28090 - /* search for header terminator
28092 - * if we start with \r\n check if last packet terminated with \r\n
28093 - * if we start with \n check if last packet terminated with \n
28094 - * search for \r\n\r\n
28095 - * search for \n\n
28098 - if (hctx->response_header->used == 0) {
28099 - buffer_copy_string_buffer(hctx->response_header, packet.b);
28101 - buffer_append_string_buffer(hctx->response_header, packet.b);
28104 - if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) {
28105 - blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 4;
28106 - hctx->response_header->used = (c - hctx->response_header->ptr) + 3;
28107 - c += 4; /* point the the start of the response */
28108 - } else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) {
28109 - blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 2;
28110 - hctx->response_header->used = c - hctx->response_header->ptr + 2;
28111 - c += 2; /* point the the start of the response */
28113 - /* no luck, no header found */
28114 + int have_content_length = 0;
28115 + int need_more = 0;
28118 + /* append the current packet to the chunk queue */
28119 + chunkqueue_append_buffer(hctx->http_rb, packet.b);
28120 + http_response_reset(p->resp);
28122 + switch(http_response_parse_cq(hctx->http_rb, p->resp)) {
28123 + case PARSE_ERROR:
28124 + /* parsing the response header failed */
28126 + con->http_status = 502; /* Bad Gateway */
28129 + case PARSE_NEED_MORE:
28131 + break; /* leave the loop */
28132 + case PARSE_SUCCESS:
28135 + /* should not happen */
28139 - /* parse the response header */
28140 - fcgi_response_parse(srv, con, p, hctx->response_header);
28141 + if (need_more) break;
28143 - con->file_started = 1;
28144 + chunkqueue_remove_finished_chunks(hctx->http_rb);
28146 - if (host->mode == FCGI_AUTHORIZER &&
28147 - (con->http_status == 0 ||
28148 - con->http_status == 200)) {
28149 - /* a authorizer with approved the static request, ignore the content here */
28150 - hctx->send_content_body = 0;
28153 - if (host->allow_xsendfile &&
28154 - NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))) {
28155 - stat_cache_entry *sce;
28157 - if (HANDLER_ERROR != stat_cache_get_entry(srv, con, ds->value, &sce)) {
28160 - http_chunk_append_file(srv, con, ds->value, 0, sce->st.st_size);
28161 - hctx->send_content_body = 0; /* ignore the content */
28162 - joblist_append(srv, con);
28163 + con->http_status = p->resp->status;
28164 + hctx->send_content_body = 1;
28166 + /* handle the header fields */
28167 + if (host->mode == FCGI_AUTHORIZER) {
28168 + /* auth mode is a bit different */
28170 + if (con->http_status == 0 ||
28171 + con->http_status == 200) {
28172 + /* a authorizer with approved the static request, ignore the content here */
28173 + hctx->send_content_body = 0;
28177 + /* copy the http-headers */
28178 + for (i = 0; i < p->resp->headers->used; i++) {
28179 + const char *ign[] = { "Status", NULL };
28183 + data_string *header = (data_string *)p->resp->headers->data[i];
28185 + /* ignore all headers in AUTHORIZER mode */
28186 + if (host->mode == FCGI_AUTHORIZER) continue;
28188 + /* some headers are ignored by default */
28189 + for (j = 0; ign[j]; j++) {
28190 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
28192 + if (ign[j]) continue;
28194 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
28195 + /* CGI/1.1 rev 03 - 7.2.1.2 */
28196 + con->http_status = 302;
28197 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
28198 + have_content_length = 1;
28199 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Sendfile")) ||
28200 + 0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-LIGHTTPD-send-file"))) {
28202 - if (hctx->send_content_body && blen > 1) {
28203 - /* enable chunked-transfer-encoding */
28204 - if (con->request.http_version == HTTP_VERSION_1_1 &&
28205 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
28206 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
28207 + stat_cache_entry *sce;
28209 + if (host->allow_xsendfile &&
28210 + HANDLER_ERROR != stat_cache_get_entry(srv, con, header->value, &sce)) {
28211 + chunkqueue_append_file(con->send, header->value, 0, sce->st.st_size);
28212 + hctx->send_content_body = 0; /* ignore the content */
28214 + joblist_append(srv, con);
28217 + continue; /* ignore header */
28220 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
28221 + ds = data_response_init();
28223 + buffer_copy_string_buffer(ds->key, header->key);
28224 + buffer_copy_string_buffer(ds->value, header->value);
28226 - http_chunk_append_mem(srv, con, c, blen);
28227 + array_insert_unique(con->response.headers, (data_unset *)ds);
28230 + /* header is complete ... go on with the body */
28232 + con->file_started = 1;
28234 + if (hctx->send_content_body) {
28235 + chunk *c = hctx->http_rb->first;
28237 + /* copy the rest of the data */
28238 + for (c = hctx->http_rb->first; c; c = c->next) {
28239 + if (c->mem->used > 1) {
28240 + chunkqueue_append_mem(con->send, c->mem->ptr + c->offset, c->mem->used - c->offset);
28241 + c->offset = c->mem->used - 1;
28244 + chunkqueue_remove_finished_chunks(hctx->http_rb);
28245 joblist_append(srv, con);
28247 } else if (hctx->send_content_body && packet.b->used > 1) {
28248 - if (con->request.http_version == HTTP_VERSION_1_1 &&
28249 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
28250 - /* enable chunked-transfer-encoding */
28251 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
28254 - http_chunk_append_mem(srv, con, packet.b->ptr, packet.b->used);
28255 + chunkqueue_append_mem(con->send, packet.b->ptr, packet.b->used);
28256 joblist_append(srv, con);
28260 - log_error_write(srv, __FILE__, __LINE__, "sb",
28261 + log_error_write(srv, __FILE__, __LINE__, "sb",
28262 "FastCGI-stderr:", packet.b);
28266 case FCGI_END_REQUEST:
28267 - con->file_finished = 1;
28269 + con->send->is_closed = 1;
28271 if (host->mode != FCGI_AUTHORIZER ||
28272 !(con->http_status == 0 ||
28273 con->http_status == 200)) {
28274 /* send chunk-end if nesseary */
28275 - http_chunk_append_mem(srv, con, NULL, 0);
28276 joblist_append(srv, con);
28283 - log_error_write(srv, __FILE__, __LINE__, "sd",
28284 + log_error_write(srv, __FILE__, __LINE__, "sd",
28285 "FastCGI: header.type not handled: ", packet.type);
28288 buffer_free(packet.b);
28295 static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_host *host) {
28299 for (proc = host->first; proc; proc = proc->next) {
28302 if (p->conf.debug > 2) {
28303 - log_error_write(srv, __FILE__, __LINE__, "sbdddd",
28305 + log_error_write(srv, __FILE__, __LINE__, "sbdddd",
28307 proc->connection_name,
28317 * if the remote side is overloaded, we check back after <n> seconds
28321 switch (proc->state) {
28322 case PROC_STATE_KILLED:
28323 @@ -2592,13 +2457,13 @@
28325 case PROC_STATE_OVERLOADED:
28326 if (srv->cur_ts <= proc->disabled_until) break;
28329 proc->state = PROC_STATE_RUNNING;
28330 host->active_procs++;
28332 - log_error_write(srv, __FILE__, __LINE__, "sbdb",
28333 - "fcgi-server re-enabled:",
28334 - host->host, host->port,
28336 + log_error_write(srv, __FILE__, __LINE__, "sbdb",
28337 + "fcgi-server re-enabled:",
28338 + host->host, host->port,
28341 case PROC_STATE_DIED_WAIT_FOR_PID:
28342 @@ -2606,7 +2471,7 @@
28343 if (!proc->is_local) break;
28345 /* the child should not terminate at all */
28348 switch(waitpid(proc->pid, &status, WNOHANG)) {
28350 /* child is still alive */
28351 @@ -2616,45 +2481,45 @@
28353 if (WIFEXITED(status)) {
28355 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
28356 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
28357 "child exited, pid:", proc->pid,
28358 "status:", WEXITSTATUS(status));
28360 } else if (WIFSIGNALED(status)) {
28361 - log_error_write(srv, __FILE__, __LINE__, "sd",
28362 - "child signaled:",
28363 + log_error_write(srv, __FILE__, __LINE__, "sd",
28364 + "child signaled:",
28367 - log_error_write(srv, __FILE__, __LINE__, "sd",
28368 - "child died somehow:",
28369 + log_error_write(srv, __FILE__, __LINE__, "sd",
28370 + "child died somehow:",
28375 proc->state = PROC_STATE_DIED;
28380 /* fall through if we have a dead proc now */
28381 if (proc->state != PROC_STATE_DIED) break;
28383 case PROC_STATE_DIED:
28384 - /* local proc get restarted by us,
28385 + /* local proc get restarted by us,
28386 * remote ones hopefully by the admin */
28389 if (proc->is_local) {
28390 /* we still have connections bound to this proc,
28391 * let them terminate first */
28392 if (proc->load != 0) break;
28395 /* restart the child */
28398 if (p->conf.debug) {
28399 log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
28400 "--- fastcgi spawning",
28401 "\n\tsocket", proc->connection_name,
28402 "\n\tcurrent:", 1, "/", host->min_procs);
28406 if (fcgi_spawn_connection(srv, p, host, proc)) {
28407 log_error_write(srv, __FILE__, __LINE__, "s",
28408 "ERROR: spawning fcgi failed.");
28409 @@ -2662,18 +2527,18 @@
28412 if (srv->cur_ts <= proc->disabled_until) break;
28415 proc->state = PROC_STATE_RUNNING;
28416 host->active_procs++;
28418 - log_error_write(srv, __FILE__, __LINE__, "sb",
28419 - "fcgi-server re-enabled:",
28421 + log_error_write(srv, __FILE__, __LINE__, "sb",
28422 + "fcgi-server re-enabled:",
28423 proc->connection_name);
28433 @@ -2682,19 +2547,19 @@
28434 fcgi_extension_host *host= hctx->host;
28435 connection *con = hctx->remote_conn;
28441 - /* sanity check */
28442 + /* sanity check */
28444 ((!host->host->used || !host->port) && !host->unixsocket->used)) {
28445 - log_error_write(srv, __FILE__, __LINE__, "sxddd",
28446 + log_error_write(srv, __FILE__, __LINE__, "sxddd",
28447 "write-req: error",
28451 host->unixsocket->used);
28454 hctx->proc->disabled_until = srv->cur_ts + 10;
28455 hctx->proc->state = PROC_STATE_DIED;
28457 @@ -2705,12 +2570,12 @@
28458 if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
28460 socklen_t socket_error_len = sizeof(socket_error);
28463 /* try to finish the connect() */
28464 - if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28465 - log_error_write(srv, __FILE__, __LINE__, "ss",
28466 + if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28467 + log_error_write(srv, __FILE__, __LINE__, "ss",
28468 "getsockopt failed:", strerror(errno));
28471 hctx->proc->disabled_until = srv->cur_ts + 10;
28472 hctx->proc->state = PROC_STATE_DIED;
28474 @@ -2719,12 +2584,12 @@
28475 if (socket_error != 0) {
28476 if (!hctx->proc->is_local || p->conf.debug) {
28477 /* local procs get restarted */
28480 log_error_write(srv, __FILE__, __LINE__, "sssb",
28481 - "establishing connection failed:", strerror(socket_error),
28482 + "establishing connection failed:", strerror(socket_error),
28483 "socket:", hctx->proc->connection_name);
28487 hctx->proc->disabled_until = srv->cur_ts + 5;
28489 if (hctx->proc->is_local) {
28490 @@ -2732,17 +2597,17 @@
28492 hctx->proc->state = PROC_STATE_DIED;
28496 hctx->proc->state = PROC_STATE_DIED;
28499 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
28500 buffer_append_string(p->statuskey, ".died");
28502 - status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
28504 + status_counter_inc(CONST_BUF_LEN(p->statuskey));
28506 return HANDLER_ERROR;
28508 - /* go on with preparing the request */
28509 + /* go on with preparing the request */
28510 hctx->state = FCGI_STATE_PREPARE_WRITE;
28513 @@ -2755,14 +2620,14 @@
28514 /* do we have a running process for this host (max-procs) ? */
28517 - for (proc = hctx->host->first;
28518 - proc && proc->state != PROC_STATE_RUNNING;
28519 + for (proc = hctx->host->first;
28520 + proc && proc->state != PROC_STATE_RUNNING;
28521 proc = proc->next);
28524 /* all childs are dead */
28525 if (proc == NULL) {
28526 - hctx->fde_ndx = -1;
28528 + hctx->sock->fde_ndx = -1;
28530 return HANDLER_ERROR;
28533 @@ -2775,50 +2640,50 @@
28536 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
28538 - if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
28540 + if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
28541 if (errno == EMFILE ||
28543 - log_error_write(srv, __FILE__, __LINE__, "sd",
28544 - "wait for fd at connection:", con->fd);
28546 + log_error_write(srv, __FILE__, __LINE__, "sd",
28547 + "wait for fd at connection:", con->sock->fd);
28549 return HANDLER_WAIT_FOR_FD;
28552 - log_error_write(srv, __FILE__, __LINE__, "ssdd",
28554 + log_error_write(srv, __FILE__, __LINE__, "ssdd",
28555 "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
28556 return HANDLER_ERROR;
28558 - hctx->fde_ndx = -1;
28560 + hctx->sock->fde_ndx = -1;
28564 - fdevent_register(srv->ev, hctx->fd, fcgi_handle_fdevent, hctx);
28566 - if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
28567 - log_error_write(srv, __FILE__, __LINE__, "ss",
28569 + fdevent_register(srv->ev, hctx->sock, fcgi_handle_fdevent, hctx);
28571 + if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
28572 + log_error_write(srv, __FILE__, __LINE__, "ss",
28573 "fcntl failed:", strerror(errno));
28576 return HANDLER_ERROR;
28580 if (hctx->proc->is_local) {
28581 hctx->pid = hctx->proc->pid;
28585 switch (fcgi_establish_connection(srv, hctx)) {
28586 case CONNECTION_DELAYED:
28587 /* connection is in progress, wait for an event and call getsockopt() below */
28589 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28592 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
28594 fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT_DELAYED);
28595 return HANDLER_WAIT_FOR_EVENT;
28596 case CONNECTION_OVERLOADED:
28597 /* cool down the backend, it is overloaded
28600 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
28601 + log_error_write(srv, __FILE__, __LINE__, "ssdsd",
28602 "backend is overloaded, we disable it for a 2 seconds and send the request to another backend instead:",
28603 "reconnects:", hctx->reconnects,
28604 "load:", host->load);
28605 @@ -2830,8 +2695,8 @@
28606 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
28607 buffer_append_string(p->statuskey, ".overloaded");
28609 - status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
28611 + status_counter_inc(CONST_BUF_LEN(p->statuskey));
28613 return HANDLER_ERROR;
28614 case CONNECTION_DEAD:
28615 /* we got a hard error from the backend like
28616 @@ -2840,67 +2705,67 @@
28618 * for check if the host is back in 5 seconds
28622 hctx->proc->disabled_until = srv->cur_ts + 5;
28623 if (hctx->proc->is_local) {
28624 hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
28626 hctx->proc->state = PROC_STATE_DIED;
28629 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
28631 + log_error_write(srv, __FILE__, __LINE__, "ssdsd",
28632 "backend died, we disable it for a 5 seconds and send the request to another backend instead:",
28633 "reconnects:", hctx->reconnects,
28634 "load:", host->load);
28637 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
28638 buffer_append_string(p->statuskey, ".died");
28640 - status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
28641 + status_counter_inc(CONST_BUF_LEN(p->statuskey));
28643 return HANDLER_ERROR;
28644 case CONNECTION_OK:
28645 /* everything is ok, go on */
28647 fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
28651 case CONNECTION_UNSET:
28656 case FCGI_STATE_PREPARE_WRITE:
28657 /* ok, we have the connection */
28660 hctx->proc->load++;
28661 hctx->proc->last_used = srv->cur_ts;
28662 hctx->got_proc = 1;
28664 - status_counter_inc(srv, CONST_STR_LEN("fastcgi.requests"));
28665 - status_counter_inc(srv, CONST_STR_LEN("fastcgi.active-requests"));
28667 + status_counter_inc(CONST_STR_LEN("fastcgi.requests"));
28668 + status_counter_inc(CONST_STR_LEN("fastcgi.active-requests"));
28670 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
28671 buffer_append_string(p->statuskey, ".connected");
28673 - status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
28674 + status_counter_inc(CONST_BUF_LEN(p->statuskey));
28676 /* the proc-load */
28677 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
28678 buffer_append_string(p->statuskey, ".load");
28680 - status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
28681 + status_counter_set(CONST_BUF_LEN(p->statuskey), hctx->proc->load);
28683 /* the host-load */
28684 fastcgi_status_copy_procname(p->statuskey, hctx->host, NULL);
28685 buffer_append_string(p->statuskey, ".load");
28687 - status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->host->load);
28688 + status_counter_set(CONST_BUF_LEN(p->statuskey), hctx->host->load);
28690 if (p->conf.debug) {
28691 log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
28693 - "pid:", hctx->proc->pid,
28694 - "socket:", hctx->proc->connection_name,
28696 + "pid:", hctx->proc->pid,
28697 + "socket:", hctx->proc->connection_name,
28698 "load:", hctx->proc->load);
28701 @@ -2908,74 +2773,75 @@
28702 if (hctx->request_id == 0) {
28703 hctx->request_id = fcgi_requestid_new(srv, p);
28705 - log_error_write(srv, __FILE__, __LINE__, "sd",
28706 + log_error_write(srv, __FILE__, __LINE__, "sd",
28707 "fcgi-request is already in use:", hctx->request_id);
28712 fcgi_create_env(srv, hctx, hctx->request_id);
28715 fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);
28719 case FCGI_STATE_WRITE:
28720 - ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
28721 + ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
28723 chunkqueue_remove_finished_chunks(hctx->wb);
28729 - /* the connection got dropped after accept()
28731 - * this is most of the time a PHP which dies
28732 + /* the connection got dropped after accept()
28734 + * this is most of the time a PHP which dies
28735 * after PHP_FCGI_MAX_REQUESTS
28740 if (hctx->wb->bytes_out == 0 &&
28741 hctx->reconnects < 5) {
28742 - usleep(10000); /* take away the load of the webserver
28743 - * to let the php a chance to restart
28745 + usleep(10000); /* take away the load of the webserver
28746 + * to let the php a chance to restart
28750 fcgi_reconnect(srv, hctx);
28753 return HANDLER_WAIT_FOR_FD;
28757 /* not reconnected ... why
28760 * far@#lighttpd report this for FreeBSD
28765 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
28767 + log_error_write(srv, __FILE__, __LINE__, "ssosd",
28768 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
28769 "write-offset:", hctx->wb->bytes_out,
28770 "reconnect attempts:", hctx->reconnects);
28773 return HANDLER_ERROR;
28776 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28778 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
28780 return HANDLER_WAIT_FOR_EVENT;
28782 - log_error_write(srv, __FILE__, __LINE__, "ssd",
28783 + log_error_write(srv, __FILE__, __LINE__, "ssd",
28784 "write failed:", strerror(errno), errno);
28787 return HANDLER_ERROR;
28791 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
28792 /* we don't need the out event anymore */
28793 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
28794 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
28795 + fdevent_event_del(srv->ev, hctx->sock);
28796 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
28797 fcgi_set_state(srv, hctx, FCGI_STATE_READ);
28799 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28801 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
28803 return HANDLER_WAIT_FOR_EVENT;
28806 @@ -2987,7 +2853,7 @@
28807 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
28808 return HANDLER_ERROR;
28812 return HANDLER_WAIT_FOR_EVENT;
28815 @@ -2996,18 +2862,18 @@
28817 SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
28818 plugin_data *p = p_d;
28821 handler_ctx *hctx = con->plugin_ctx[p->id];
28823 fcgi_extension_host *host;
28826 if (NULL == hctx) return HANDLER_GO_ON;
28830 if (con->mode != p->id) return HANDLER_GO_ON;
28832 /* we don't have a host yet, choose one
28833 - * -> this happens in the first round
28834 + * -> this happens in the first round
28835 * and when the host died and we have to select a new one */
28836 if (hctx->host == NULL) {
28838 @@ -3016,23 +2882,23 @@
28839 /* get best server */
28840 for (k = 0, ndx = -1; k < hctx->ext->used; k++) {
28841 host = hctx->ext->hosts[k];
28844 /* we should have at least one proc that can do something */
28845 if (host->active_procs == 0) continue;
28847 if (used == -1 || host->load < used) {
28856 /* found a server */
28858 /* all hosts are down */
28860 fcgi_connection_close(srv, hctx);
28863 con->http_status = 500;
28864 con->mode = DIRECT;
28866 @@ -3040,16 +2906,16 @@
28869 host = hctx->ext->hosts[ndx];
28872 - * if check-local is disabled, use the uri.path handler
28876 + * if check-local is disabled, use the uri.path handler
28881 /* init handler-context */
28884 - /* we put a connection on this host, move the other new connections to other hosts
28885 + /* we put a connection on this host, move the other new connections to other hosts
28887 * as soon as hctx->host is unassigned, decrease the load again */
28888 hctx->host->load++;
28889 @@ -3063,7 +2929,7 @@
28890 case HANDLER_ERROR:
28895 if (hctx->state == FCGI_STATE_INIT ||
28896 hctx->state == FCGI_STATE_CONNECT_DELAYED) {
28897 if (proc) host->active_procs--;
28898 @@ -3078,7 +2944,7 @@
28899 return HANDLER_WAIT_FOR_FD;
28901 fcgi_connection_close(srv, hctx);
28904 buffer_reset(con->physical.path);
28905 con->mode = DIRECT;
28906 con->http_status = 500;
28907 @@ -3088,12 +2954,12 @@
28910 fcgi_connection_close(srv, hctx);
28913 buffer_reset(con->physical.path);
28914 con->mode = DIRECT;
28915 con->http_status = 503;
28916 joblist_append(srv, con); /* really ? */
28919 return HANDLER_FINISHED;
28921 case HANDLER_WAIT_FOR_EVENT:
28922 @@ -3115,7 +2981,7 @@
28923 handler_ctx *hctx = ctx;
28924 connection *con = hctx->remote_conn;
28925 plugin_data *p = hctx->plugin_data;
28928 fcgi_proc *proc = hctx->proc;
28929 fcgi_extension_host *host= hctx->host;
28931 @@ -3125,8 +2991,8 @@
28936 - if (host->mode == FCGI_AUTHORIZER &&
28938 + if (host->mode == FCGI_AUTHORIZER &&
28939 (con->http_status == 200 ||
28940 con->http_status == 0)) {
28942 @@ -3136,26 +3002,26 @@
28945 buffer_copy_string_buffer(con->physical.doc_root, host->docroot);
28948 buffer_copy_string_buffer(con->physical.path, host->docroot);
28949 buffer_append_string_buffer(con->physical.path, con->uri.path);
28950 fcgi_connection_close(srv, hctx);
28953 con->mode = DIRECT;
28954 con->file_started = 1; /* fcgi_extension won't touch the request afterwards */
28957 fcgi_connection_close(srv, hctx);
28961 joblist_append(srv, con);
28962 return HANDLER_FINISHED;
28964 if (proc->pid && proc->state != PROC_STATE_DIED) {
28968 /* only fetch the zombie if it is not already done */
28971 switch(waitpid(proc->pid, &status, WNOHANG)) {
28973 /* child is still alive */
28974 @@ -3165,137 +3031,137 @@
28976 /* the child should not terminate at all */
28977 if (WIFEXITED(status)) {
28978 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
28979 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
28980 "child exited, pid:", proc->pid,
28981 "status:", WEXITSTATUS(status));
28982 } else if (WIFSIGNALED(status)) {
28983 - log_error_write(srv, __FILE__, __LINE__, "sd",
28984 - "child signaled:",
28985 + log_error_write(srv, __FILE__, __LINE__, "sd",
28986 + "child signaled:",
28989 - log_error_write(srv, __FILE__, __LINE__, "sd",
28990 - "child died somehow:",
28991 + log_error_write(srv, __FILE__, __LINE__, "sd",
28992 + "child died somehow:",
28997 if (p->conf.debug) {
28998 log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
28999 "--- fastcgi spawning",
29000 "\n\tsocket", proc->connection_name,
29001 "\n\tcurrent:", 1, "/", host->min_procs);
29005 if (fcgi_spawn_connection(srv, p, host, proc)) {
29006 /* respawning failed, retry later */
29007 proc->state = PROC_STATE_DIED;
29009 - log_error_write(srv, __FILE__, __LINE__, "s",
29010 + log_error_write(srv, __FILE__, __LINE__, "s",
29011 "respawning failed, will retry later");
29020 if (con->file_started == 0) {
29021 /* nothing has been send out yet, try to use another child */
29024 if (hctx->wb->bytes_out == 0 &&
29025 hctx->reconnects < 5) {
29026 fcgi_reconnect(srv, hctx);
29028 - log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
29030 + log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
29031 "response not received, request not sent",
29032 - "on socket:", proc->connection_name,
29033 + "on socket:", proc->connection_name,
29034 "for", con->uri.path, ", reconnecting");
29037 return HANDLER_WAIT_FOR_FD;
29040 - log_error_write(srv, __FILE__, __LINE__, "sosbsbs",
29042 + log_error_write(srv, __FILE__, __LINE__, "sosbsbs",
29043 "response not received, request sent:", hctx->wb->bytes_out,
29044 - "on socket:", proc->connection_name,
29045 + "on socket:", proc->connection_name,
29046 "for", con->uri.path, ", closing connection");
29049 fcgi_connection_close(srv, hctx);
29051 - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
29053 buffer_reset(con->physical.path);
29054 con->http_status = 500;
29055 con->mode = DIRECT;
29057 /* response might have been already started, kill the connection */
29058 fcgi_connection_close(srv, hctx);
29060 - log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
29062 + log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
29063 "response already sent out, but backend returned error",
29064 - "on socket:", proc->connection_name,
29065 + "on socket:", proc->connection_name,
29066 "for", con->uri.path, ", terminating connection");
29069 connection_set_state(srv, con, CON_STATE_ERROR);
29077 joblist_append(srv, con);
29078 return HANDLER_FINISHED;
29083 if (revents & FDEVENT_OUT) {
29084 if (hctx->state == FCGI_STATE_CONNECT_DELAYED ||
29085 hctx->state == FCGI_STATE_WRITE) {
29086 /* we are allowed to send something out
29089 * 1. in a unfinished connect() call
29090 * 2. in a unfinished write() call (long POST request)
29092 return mod_fastcgi_handle_subrequest(srv, con, p);
29094 - log_error_write(srv, __FILE__, __LINE__, "sd",
29095 - "got a FDEVENT_OUT and didn't know why:",
29096 + log_error_write(srv, __FILE__, __LINE__, "sd",
29097 + "got a FDEVENT_OUT and didn't know why:",
29103 /* perhaps this issue is already handled */
29104 if (revents & FDEVENT_HUP) {
29105 if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
29106 /* getoptsock will catch this one (right ?)
29108 - * if we are in connect we might get a EINPROGRESS
29109 - * in the first call and a FDEVENT_HUP in the
29111 + * if we are in connect we might get a EINPROGRESS
29112 + * in the first call and a FDEVENT_HUP in the
29116 * FIXME: as it is a bit ugly.
29120 return mod_fastcgi_handle_subrequest(srv, con, p);
29121 } else if (hctx->state == FCGI_STATE_READ &&
29122 hctx->proc->port == 0) {
29126 * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
29127 * even if the FCGI_FIN packet is not received yet
29130 - log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
29131 - "error: unexpected close of fastcgi connection for",
29132 + log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
29133 + "error: unexpected close of fastcgi connection for",
29135 - "(no fastcgi process on host:",
29136 + "(no fastcgi process on host:",
29145 connection_set_state(srv, con, CON_STATE_ERROR);
29146 fcgi_connection_close(srv, hctx);
29147 joblist_append(srv, con);
29149 } else if (revents & FDEVENT_ERR) {
29150 - log_error_write(srv, __FILE__, __LINE__, "s",
29151 + log_error_write(srv, __FILE__, __LINE__, "s",
29152 "fcgi: got a FDEVENT_ERR. Don't know why.");
29153 /* kill all connections to the fastcgi process */
29155 @@ -3304,45 +3170,42 @@
29156 fcgi_connection_close(srv, hctx);
29157 joblist_append(srv, con);
29161 return HANDLER_FINISHED;
29163 -#define PATCH(x) \
29164 - p->conf.x = s->x;
29166 static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
29168 plugin_config *s = p->config_storage[0];
29172 - PATCH(ext_mapping);
29175 + PATCH_OPTION(exts);
29176 + PATCH_OPTION(debug);
29177 + PATCH_OPTION(ext_mapping);
29179 /* skip the first, the global context */
29180 for (i = 1; i < srv->config_context->used; i++) {
29181 data_config *dc = (data_config *)srv->config_context->data[i];
29182 s = p->config_storage[i];
29185 /* condition didn't match */
29186 if (!config_check_cond(srv, con, dc)) continue;
29190 for (j = 0; j < dc->value->used; j++) {
29191 data_unset *du = dc->value->data[j];
29194 if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.server"))) {
29196 + PATCH_OPTION(exts);
29197 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.debug"))) {
29199 + PATCH_OPTION(debug);
29200 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.map-extensions"))) {
29201 - PATCH(ext_mapping);
29202 + PATCH_OPTION(ext_mapping);
29213 static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
29214 plugin_data *p = p_d;
29215 @@ -3351,16 +3214,16 @@
29217 fcgi_extension *extension = NULL;
29218 fcgi_extension_host *host = NULL;
29221 /* Possibly, we processed already this request */
29222 if (con->file_started == 1) return HANDLER_GO_ON;
29224 fn = uri_path_handler ? con->uri.path : con->physical.path;
29226 if (buffer_is_empty(fn)) return HANDLER_GO_ON;
29229 s_len = fn->used - 1;
29232 fcgi_patch_connection(srv, con, p);
29234 /* fastcgi.map-extensions maps extensions to existing fastcgi.server entries
29235 @@ -3368,24 +3231,24 @@
29236 * fastcgi.map-extensions = ( ".php3" => ".php" )
29238 * fastcgi.server = ( ".php" => ... )
29243 /* check if extension-mapping matches */
29244 for (k = 0; k < p->conf.ext_mapping->used; k++) {
29245 data_string *ds = (data_string *)p->conf.ext_mapping->data[k];
29246 size_t ct_len; /* length of the config entry */
29249 if (ds->key->used == 0) continue;
29252 ct_len = ds->key->used - 1;
29255 if (s_len < ct_len) continue;
29258 /* found a mapping */
29259 if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
29260 /* check if we know the extension */
29263 /* we can reuse k here */
29264 for (k = 0; k < p->conf.exts->used; k++) {
29265 extension = p->conf.exts->exts[k];
29266 @@ -3407,15 +3270,15 @@
29267 /* check if extension matches */
29268 for (k = 0; k < p->conf.exts->used; k++) {
29269 size_t ct_len; /* length of the config entry */
29272 extension = p->conf.exts->exts[k];
29275 if (extension->key->used == 0) continue;
29278 ct_len = extension->key->used - 1;
29281 if (s_len < ct_len) continue;
29284 /* check extension in the form "/fcgi_pattern" */
29285 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
29287 @@ -3441,10 +3304,10 @@
29291 - /* we found one host that is alive */
29292 + /* we found one host that is alive */
29298 /* sorry, we don't have a server alive for this ext */
29299 buffer_reset(con->physical.path);
29300 @@ -3459,72 +3322,72 @@
29301 "on", extension->key,
29306 return HANDLER_FINISHED;
29309 /* a note about no handler is not sent yey */
29310 extension->note_is_sent = 0;
29313 - * if check-local is disabled, use the uri.path handler
29316 + * if check-local is disabled, use the uri.path handler
29321 /* init handler-context */
29322 if (uri_path_handler) {
29323 if (host->check_local == 0) {
29328 hctx = handler_ctx_init();
29331 hctx->remote_conn = con;
29332 hctx->plugin_data = p;
29334 hctx->ext = extension;
29338 hctx->conf.exts = p->conf.exts;
29339 hctx->conf.debug = p->conf.debug;
29342 con->plugin_ctx[p->id] = hctx;
29348 if (con->conf.log_request_handling) {
29349 - log_error_write(srv, __FILE__, __LINE__, "s",
29350 + log_error_write(srv, __FILE__, __LINE__, "s",
29351 "handling it in mod_fastcgi");
29354 - /* the prefix is the SCRIPT_NAME,
29356 + /* the prefix is the SCRIPT_NAME,
29357 * everthing from start to the next slash
29358 * this is important for check-local = "disable"
29361 * if prefix = /admin.fcgi
29364 * /admin.fcgi/foo/bar
29367 * SCRIPT_NAME = /admin.fcgi
29368 * PATH_INFO = /foo/bar
29371 * if prefix = /fcgi-bin/
29374 * /fcgi-bin/foo/bar
29377 * SCRIPT_NAME = /fcgi-bin/foo
29384 /* the rewrite is only done for /prefix/? matches */
29385 if (extension->key->ptr[0] == '/' &&
29386 con->uri.path->used > extension->key->used &&
29387 NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
29388 - /* rewrite uri.path and pathinfo */
29390 + /* rewrite uri.path and pathinfo */
29392 buffer_copy_string(con->request.pathinfo, pathinfo);
29395 con->uri.path->used -= con->request.pathinfo->used - 1;
29396 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
29398 @@ -3532,19 +3395,19 @@
29401 hctx = handler_ctx_init();
29404 hctx->remote_conn = con;
29405 hctx->plugin_data = p;
29407 hctx->ext = extension;
29410 hctx->conf.exts = p->conf.exts;
29411 hctx->conf.debug = p->conf.debug;
29414 con->plugin_ctx[p->id] = hctx;
29420 if (con->conf.log_request_handling) {
29421 log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
29423 @@ -3566,19 +3429,19 @@
29424 JOBLIST_FUNC(mod_fastcgi_handle_joblist) {
29425 plugin_data *p = p_d;
29426 handler_ctx *hctx = con->plugin_ctx[p->id];
29429 if (hctx == NULL) return HANDLER_GO_ON;
29431 - if (hctx->fd != -1) {
29432 + if (hctx->sock->fd != -1) {
29433 switch (hctx->state) {
29434 case FCGI_STATE_READ:
29435 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
29437 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
29440 case FCGI_STATE_CONNECT_DELAYED:
29441 case FCGI_STATE_WRITE:
29442 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
29444 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
29447 case FCGI_STATE_INIT:
29449 @@ -3595,7 +3458,7 @@
29451 static handler_t fcgi_connection_close_callback(server *srv, connection *con, void *p_d) {
29452 plugin_data *p = p_d;
29455 fcgi_connection_close(srv, con->plugin_ctx[p->id]);
29457 return HANDLER_GO_ON;
29458 @@ -3604,16 +3467,38 @@
29459 TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
29460 plugin_data *p = p_d;
29466 /* perhaps we should kill a connect attempt after 10-15 seconds
29469 * currently we wait for the TCP timeout which is on Linux 180 seconds
29476 + for (i = 0; i < srv->conns->used; i++) {
29477 + connection *con = srv->conns->ptr[i];
29478 + handler_ctx *hctx = con->plugin_ctx[p->id];
29480 + /* if a connection is ours and is in handle-req for more than max-request-time
29481 + * kill the connection */
29483 + if (con->mode != p->id) continue;
29484 + if (srv->cur_ts < con->request_start + 60) continue;
29486 + /* the request is waiting for a FCGI_STDOUT since 60 seconds */
29488 + /* kill the connection */
29490 + log_error_write(srv, __FILE__, __LINE__, "s", "fastcgi backend didn't responded after 60 seconds");
29492 + fcgi_connection_close(srv, hctx);
29494 + con->mode = DIRECT;
29495 + con->http_status = 500;
29497 + joblist_append(srv, con);
29500 /* check all childs if they are still up */
29502 for (i = 0; i < srv->config_context->used; i++) {
29503 @@ -3628,45 +3513,45 @@
29504 fcgi_extension *ex;
29506 ex = exts->exts[j];
29509 for (n = 0; n < ex->used; n++) {
29513 unsigned long sum_load = 0;
29514 fcgi_extension_host *host;
29517 host = ex->hosts[n];
29520 fcgi_restart_dead_procs(srv, p, host);
29523 for (proc = host->first; proc; proc = proc->next) {
29524 sum_load += proc->load;
29528 if (host->num_procs &&
29529 host->num_procs < host->max_procs &&
29530 (sum_load / host->num_procs) > host->max_load_per_proc) {
29531 /* overload, spawn new child */
29532 if (p->conf.debug) {
29533 - log_error_write(srv, __FILE__, __LINE__, "s",
29534 + log_error_write(srv, __FILE__, __LINE__, "s",
29535 "overload detected, spawning a new child");
29539 for (proc = host->unused_procs; proc && proc->pid != 0; proc = proc->next);
29543 if (proc == host->unused_procs) host->unused_procs = proc->next;
29546 if (proc->next) proc->next->prev = NULL;
29551 proc = fastcgi_process_init();
29552 proc->id = host->max_id++;
29559 if (buffer_is_empty(host->unixsocket)) {
29560 proc->port = host->port + proc->id;
29562 @@ -3674,13 +3559,13 @@
29563 buffer_append_string(proc->unixsocket, "-");
29564 buffer_append_long(proc->unixsocket, proc->id);
29568 if (fcgi_spawn_connection(srv, p, host, proc)) {
29569 log_error_write(srv, __FILE__, __LINE__, "s",
29570 "ERROR: spawning fcgi failed.");
29571 return HANDLER_ERROR;
29576 proc->next = host->first;
29578 @@ -3688,56 +3573,56 @@
29580 host->first = proc;
29584 for (proc = host->first; proc; proc = proc->next) {
29585 if (proc->load != 0) break;
29586 if (host->num_procs <= host->min_procs) break;
29587 if (proc->pid == 0) continue;
29590 if (srv->cur_ts - proc->last_used > host->idle_timeout) {
29591 /* a proc is idling for a long time now,
29595 if (p->conf.debug) {
29596 - log_error_write(srv, __FILE__, __LINE__, "ssbsd",
29597 - "idle-timeout reached, terminating child:",
29598 - "socket:", proc->connection_name,
29599 + log_error_write(srv, __FILE__, __LINE__, "ssbsd",
29600 + "idle-timeout reached, terminating child:",
29601 + "socket:", proc->connection_name,
29608 if (proc->next) proc->next->prev = proc->prev;
29609 if (proc->prev) proc->prev->next = proc->next;
29612 if (proc->prev == NULL) host->first = proc->next;
29616 proc->next = host->unused_procs;
29619 if (host->unused_procs) host->unused_procs->prev = proc;
29620 host->unused_procs = proc;
29623 kill(proc->pid, SIGTERM);
29626 proc->state = PROC_STATE_KILLED;
29628 - log_error_write(srv, __FILE__, __LINE__, "ssbsd",
29630 - "socket:", proc->connection_name,
29632 + log_error_write(srv, __FILE__, __LINE__, "ssbsd",
29634 + "socket:", proc->connection_name,
29641 /* proc is now in unused, let the next second handle the next process */
29648 for (proc = host->unused_procs; proc; proc = proc->next) {
29652 if (proc->pid == 0) continue;
29655 switch (waitpid(proc->pid, &status, WNOHANG)) {
29657 /* child still running after timeout, good */
29658 @@ -3745,10 +3630,10 @@
29660 if (errno != EINTR) {
29661 /* no PID found ? should never happen */
29662 - log_error_write(srv, __FILE__, __LINE__, "sddss",
29663 + log_error_write(srv, __FILE__, __LINE__, "sddss",
29664 "pid ", proc->pid, proc->state,
29665 "not found:", strerror(errno));
29669 if (errno == ECHILD) {
29670 /* someone else has cleaned up for us */
29671 @@ -3762,25 +3647,26 @@
29672 /* the child should not terminate at all */
29673 if (WIFEXITED(status)) {
29674 if (proc->state != PROC_STATE_KILLED) {
29675 - log_error_write(srv, __FILE__, __LINE__, "sdb",
29677 + log_error_write(srv, __FILE__, __LINE__, "sdb",
29679 WEXITSTATUS(status), proc->connection_name);
29681 } else if (WIFSIGNALED(status)) {
29682 if (WTERMSIG(status) != SIGTERM) {
29683 - log_error_write(srv, __FILE__, __LINE__, "sd",
29684 - "child signaled:",
29685 + log_error_write(srv, __FILE__, __LINE__, "sd",
29686 + "child signaled:",
29690 - log_error_write(srv, __FILE__, __LINE__, "sd",
29691 - "child died somehow:",
29692 + log_error_write(srv, __FILE__, __LINE__, "sd",
29693 + "child died somehow:",
29697 proc->state = PROC_STATE_UNSET;
29704 @@ -3800,12 +3686,12 @@
29705 p->connection_reset = fcgi_connection_reset;
29706 p->handle_connection_close = fcgi_connection_close_callback;
29707 p->handle_uri_clean = fcgi_check_extension_1;
29708 - p->handle_subrequest_start = fcgi_check_extension_2;
29709 - p->handle_subrequest = mod_fastcgi_handle_subrequest;
29710 + p->handle_start_backend = fcgi_check_extension_2;
29711 + p->handle_send_request_content = mod_fastcgi_handle_subrequest;
29712 p->handle_joblist = mod_fastcgi_handle_joblist;
29713 p->handle_trigger = mod_fastcgi_handle_trigger;
29721 --- ../lighttpd-1.4.11/src/mod_flv_streaming.c 2006-03-07 14:06:26.000000000 +0200
29722 +++ lighttpd-1.5.0/src/mod_flv_streaming.c 2006-09-07 00:57:05.000000000 +0300
29725 #include "buffer.h"
29726 #include "response.h"
29727 -#include "http_chunk.h"
29728 #include "stat_cache.h"
29730 #include "plugin.h"
29731 @@ -23,35 +22,35 @@
29741 plugin_config **config_storage;
29743 - plugin_config conf;
29745 + plugin_config conf;
29748 /* init the plugin data */
29749 INIT_FUNC(mod_flv_streaming_init) {
29753 p = calloc(1, sizeof(*p));
29756 p->query_str = buffer_init();
29757 p->get_params = array_init();
29763 /* detroy the plugin data */
29764 FREE_FUNC(mod_flv_streaming_free) {
29765 plugin_data *p = p_d;
29770 if (!p) return HANDLER_GO_ON;
29773 if (p->config_storage) {
29776 @@ -59,19 +58,19 @@
29777 plugin_config *s = p->config_storage[i];
29782 array_free(s->extensions);
29787 free(p->config_storage);
29791 buffer_free(p->query_str);
29792 array_free(p->get_params);
29798 return HANDLER_GO_ON;
29801 @@ -80,83 +79,80 @@
29802 SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) {
29803 plugin_data *p = p_d;
29806 - config_values_t cv[] = {
29808 + config_values_t cv[] = {
29809 { "flv-streaming.extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
29810 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
29814 if (!p) return HANDLER_ERROR;
29817 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
29820 for (i = 0; i < srv->config_context->used; i++) {
29824 s = calloc(1, sizeof(plugin_config));
29825 s->extensions = array_init();
29828 cv[0].destination = s->extensions;
29831 p->config_storage[i] = s;
29834 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
29835 return HANDLER_ERROR;
29840 return HANDLER_GO_ON;
29843 -#define PATCH(x) \
29844 - p->conf.x = s->x;
29845 static int mod_flv_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
29847 plugin_config *s = p->config_storage[0];
29849 - PATCH(extensions);
29852 + PATCH_OPTION(extensions);
29854 /* skip the first, the global context */
29855 for (i = 1; i < srv->config_context->used; i++) {
29856 data_config *dc = (data_config *)srv->config_context->data[i];
29857 s = p->config_storage[i];
29860 /* condition didn't match */
29861 if (!config_check_cond(srv, con, dc)) continue;
29865 for (j = 0; j < dc->value->used; j++) {
29866 data_unset *du = dc->value->data[j];
29869 if (buffer_is_equal_string(du->key, CONST_STR_LEN("flv-streaming.extensions"))) {
29870 - PATCH(extensions);
29871 + PATCH_OPTION(extensions);
29881 -static int split_get_params(server *srv, connection *con, array *get_params, buffer *qrystr) {
29882 +static int split_get_params(array *get_params, buffer *qrystr) {
29885 char *key = NULL, *val = NULL;
29891 /* we need the \0 */
29892 for (i = 0; i < qrystr->used; i++) {
29893 switch(qrystr->ptr[i]) {
29896 val = qrystr->ptr + i + 1;
29899 qrystr->ptr[i] = '\0';
29908 case '\0': /* fin symbol */
29909 @@ -167,7 +163,7 @@
29910 /* terminate the value */
29911 qrystr->ptr[i] = '\0';
29913 - if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
29914 + if (NULL == (ds = (data_string *)array_get_unused_element(get_params, TYPE_STRING))) {
29915 ds = data_string_init();
29917 buffer_copy_string_len(ds->key, key, strlen(key));
29918 @@ -175,14 +171,14 @@
29920 array_insert_unique(get_params, (data_unset *)ds);
29924 key = qrystr->ptr + i + 1;
29935 @@ -190,34 +186,34 @@
29936 plugin_data *p = p_d;
29943 if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
29946 mod_flv_streaming_patch_connection(srv, con, p);
29948 s_len = con->physical.path->used - 1;
29951 for (k = 0; k < p->conf.extensions->used; k++) {
29952 data_string *ds = (data_string *)p->conf.extensions->data[k];
29953 int ct_len = ds->value->used - 1;
29956 if (ct_len > s_len) continue;
29957 if (ds->value->used == 0) continue;
29960 if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
29961 data_string *get_param;
29962 stat_cache_entry *sce = NULL;
29966 - /* if there is a start=[0-9]+ in the header use it as start,
29967 + /* if there is a start=[0-9]+ in the header use it as start,
29968 * otherwise send the full file */
29970 array_reset(p->get_params);
29971 buffer_copy_string_buffer(p->query_str, con->uri.query);
29972 - split_get_params(srv, con, p->get_params, p->query_str);
29973 + split_get_params(p->get_params, p->query_str);
29975 if (NULL == (get_param = (data_string *)array_get_element(p->get_params, "start"))) {
29976 return HANDLER_GO_ON;
29977 @@ -244,19 +240,19 @@
29980 /* we are safe now, let's build a flv header */
29981 - b = chunkqueue_get_append_buffer(con->write_queue);
29982 + b = chunkqueue_get_append_buffer(con->send);
29983 BUFFER_COPY_STRING_CONST(b, "FLV\x1\x1\0\0\0\x9\0\0\0\x9");
29985 - http_chunk_append_file(srv, con, con->physical.path, start, sce->st.st_size - start);
29986 + chunkqueue_append_file(con->send, con->physical.path, start, sce->st.st_size - start);
29988 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("video/x-flv"));
29990 - con->file_finished = 1;
29991 + con->send->is_closed = 1;
29993 return HANDLER_FINISHED;
29999 return HANDLER_GO_ON;
30001 @@ -266,13 +262,13 @@
30002 int mod_flv_streaming_plugin_init(plugin *p) {
30003 p->version = LIGHTTPD_VERSION_ID;
30004 p->name = buffer_init_string("flv_streaming");
30007 p->init = mod_flv_streaming_init;
30008 p->handle_physical = mod_flv_streaming_path_handler;
30009 p->set_defaults = mod_flv_streaming_set_defaults;
30010 p->cleanup = mod_flv_streaming_free;
30018 --- ../lighttpd-1.4.11/src/mod_indexfile.c 2005-09-30 01:08:53.000000000 +0300
30019 +++ lighttpd-1.5.0/src/mod_indexfile.c 2006-09-07 00:57:05.000000000 +0300
30022 #include "stat_cache.h"
30024 +#include "sys-strings.h"
30025 +#include "sys-files.h"
30026 /* plugin config for all request/connections */
30029 @@ -20,51 +22,51 @@
30038 plugin_config **config_storage;
30040 - plugin_config conf;
30042 + plugin_config conf;
30045 /* init the plugin data */
30046 INIT_FUNC(mod_indexfile_init) {
30050 p = calloc(1, sizeof(*p));
30053 p->tmp_buf = buffer_init();
30059 /* detroy the plugin data */
30060 FREE_FUNC(mod_indexfile_free) {
30061 plugin_data *p = p_d;
30066 if (!p) return HANDLER_GO_ON;
30069 if (p->config_storage) {
30071 for (i = 0; i < srv->config_context->used; i++) {
30072 plugin_config *s = p->config_storage[i];
30077 array_free(s->indexfiles);
30082 free(p->config_storage);
30086 buffer_free(p->tmp_buf);
30092 return HANDLER_GO_ON;
30095 @@ -73,131 +75,139 @@
30096 SETDEFAULTS_FUNC(mod_indexfile_set_defaults) {
30097 plugin_data *p = p_d;
30100 - config_values_t cv[] = {
30102 + config_values_t cv[] = {
30103 { "index-file.names", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
30104 { "server.indexfiles", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
30105 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
30109 if (!p) return HANDLER_ERROR;
30112 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
30115 for (i = 0; i < srv->config_context->used; i++) {
30119 s = calloc(1, sizeof(plugin_config));
30120 s->indexfiles = array_init();
30123 cv[0].destination = s->indexfiles;
30124 cv[1].destination = s->indexfiles; /* old name for [0] */
30127 p->config_storage[i] = s;
30130 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
30131 return HANDLER_ERROR;
30136 return HANDLER_GO_ON;
30139 -#define PATCH(x) \
30140 - p->conf.x = s->x;
30141 static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_data *p) {
30143 plugin_config *s = p->config_storage[0];
30145 - PATCH(indexfiles);
30148 + PATCH_OPTION(indexfiles);
30150 /* skip the first, the global context */
30151 for (i = 1; i < srv->config_context->used; i++) {
30152 data_config *dc = (data_config *)srv->config_context->data[i];
30153 s = p->config_storage[i];
30156 /* condition didn't match */
30157 if (!config_check_cond(srv, con, dc)) continue;
30161 for (j = 0; j < dc->value->used; j++) {
30162 data_unset *du = dc->value->data[j];
30165 if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.indexfiles"))) {
30166 - PATCH(indexfiles);
30167 + PATCH_OPTION(indexfiles);
30168 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("index-file.names"))) {
30169 - PATCH(indexfiles);
30170 + PATCH_OPTION(indexfiles);
30180 URIHANDLER_FUNC(mod_indexfile_subrequest) {
30181 plugin_data *p = p_d;
30183 stat_cache_entry *sce = NULL;
30186 if (con->uri.path->used == 0) return HANDLER_GO_ON;
30187 if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
30190 mod_indexfile_patch_connection(srv, con, p);
30193 + /* is the physical-path really a dir ? */
30194 + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
30195 + return HANDLER_GO_ON;
30198 + if (!S_ISDIR(sce->st.st_mode)) {
30199 + return HANDLER_GO_ON;
30202 if (con->conf.log_request_handling) {
30203 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Indexfile");
30204 log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
30210 for (k = 0; k < p->conf.indexfiles->used; k++) {
30211 data_string *ds = (data_string *)p->conf.indexfiles->data[k];
30214 if (ds->value && ds->value->ptr[0] == '/') {
30215 - /* if the index-file starts with a prefix as use this file as
30216 + /* if the index-file starts with a prefix as use this file as
30217 * index-generator */
30218 buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
30220 buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
30221 + PATHNAME_APPEND_SLASH(p->tmp_buf);
30223 buffer_append_string_buffer(p->tmp_buf, ds->value);
30226 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
30227 if (errno == EACCES) {
30228 con->http_status = 403;
30229 buffer_reset(con->physical.path);
30232 return HANDLER_FINISHED;
30236 if (errno != ENOENT &&
30237 errno != ENOTDIR) {
30238 /* we have no idea what happend. let's tell the user so. */
30241 con->http_status = 500;
30244 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
30245 "file not found ... or so: ", strerror(errno),
30247 "->", con->physical.path);
30250 buffer_reset(con->physical.path);
30253 return HANDLER_FINISHED;
30259 /* rewrite uri.path to the real path (/ -> /index.php) */
30260 buffer_append_string_buffer(con->uri.path, ds->value);
30261 buffer_copy_string_buffer(con->physical.path, p->tmp_buf);
30264 /* fce is already set up a few lines above */
30267 return HANDLER_GO_ON;
30272 return HANDLER_GO_ON;
30274 @@ -207,13 +217,13 @@
30275 int mod_indexfile_plugin_init(plugin *p) {
30276 p->version = LIGHTTPD_VERSION_ID;
30277 p->name = buffer_init_string("indexfile");
30280 p->init = mod_indexfile_init;
30281 - p->handle_subrequest_start = mod_indexfile_subrequest;
30282 + p->handle_start_backend = mod_indexfile_subrequest;
30283 p->set_defaults = mod_indexfile_set_defaults;
30284 p->cleanup = mod_indexfile_free;
30292 --- ../lighttpd-1.4.11/src/mod_mysql_vhost.c 2006-01-14 20:35:10.000000000 +0200
30293 +++ lighttpd-1.5.0/src/mod_mysql_vhost.c 2006-07-20 00:57:19.000000000 +0300
30295 -#include <unistd.h>
30299 -#include <strings.h>
30300 +#include <string.h>
30302 #ifdef HAVE_CONFIG_H
30303 #include "config.h"
30306 +#ifdef HAVE_MYSQL_H
30307 +# ifdef HAVE_LIBMYSQL
30308 +# define HAVE_MYSQL
30315 @@ -16,61 +21,40 @@
30318 #include "stat_cache.h"
30319 -#ifdef DEBUG_MOD_MYSQL_VHOST
30322 +#include "sys-files.h"
30325 - * Plugin for lighttpd to use MySQL
30326 - * for domain to directory lookups,
30327 - * i.e virtual hosts (vhosts).
30329 - * Optionally sets fcgi_offset and fcgi_arg
30330 - * in preparation for fcgi.c to handle
30331 - * per-user fcgi chroot jails.
30333 - * /ada@riksnet.se 2004-12-06
30335 +#include "mod_sql_vhost_core.h"
30339 +#define CORE_PLUGIN "mod_sql_vhost_core"
30349 - buffer *hostname;
30350 - unsigned short port;
30354 buffer *mysql_post;
30356 + mod_sql_vhost_core_plugin_config *core;
30359 /* global plugin data */
30367 plugin_config **config_storage;
30369 - plugin_config conf;
30371 + plugin_config conf;
30374 -/* per connection plugin data */
30376 - buffer *server_name;
30377 - buffer *document_root;
30378 - buffer *fcgi_arg;
30379 - unsigned fcgi_offset;
30380 -} plugin_connection_data;
30381 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost);
30383 /* init the plugin data */
30384 INIT_FUNC(mod_mysql_vhost_init) {
30388 p = calloc(1, sizeof(*p));
30390 p->tmp_buf = buffer_init();
30391 @@ -83,144 +67,77 @@
30392 plugin_data *p = p_d;
30397 - log_error_write(srv, __FILE__, __LINE__, "ss",
30398 - "mod_mysql_vhost_cleanup", p ? "yes" : "NO");
30401 if (!p) return HANDLER_GO_ON;
30404 if (p->config_storage) {
30406 for (i = 0; i < srv->config_context->used; i++) {
30407 plugin_config *s = p->config_storage[i];
30412 mysql_close(s->mysql);
30414 - buffer_free(s->mydb);
30415 - buffer_free(s->myuser);
30416 - buffer_free(s->mypass);
30417 - buffer_free(s->mysock);
30419 buffer_free(s->mysql_pre);
30420 buffer_free(s->mysql_post);
30425 free(p->config_storage);
30427 buffer_free(p->tmp_buf);
30431 - return HANDLER_GO_ON;
30434 -/* handle the plugin per connection data */
30435 -static void* mod_mysql_vhost_connection_data(server *srv, connection *con, void *p_d)
30437 - plugin_data *p = p_d;
30438 - plugin_connection_data *c = con->plugin_ctx[p->id];
30443 - log_error_write(srv, __FILE__, __LINE__, "ss",
30444 - "mod_mysql_connection_data", c ? "old" : "NEW");
30448 - c = calloc(1, sizeof(*c));
30450 - c->server_name = buffer_init();
30451 - c->document_root = buffer_init();
30452 - c->fcgi_arg = buffer_init();
30453 - c->fcgi_offset = 0;
30455 - return con->plugin_ctx[p->id] = c;
30458 -/* destroy the plugin per connection data */
30459 -CONNECTION_FUNC(mod_mysql_vhost_handle_connection_close) {
30460 - plugin_data *p = p_d;
30461 - plugin_connection_data *c = con->plugin_ctx[p->id];
30466 - log_error_write(srv, __FILE__, __LINE__, "ss",
30467 - "mod_mysql_vhost_handle_connection_close", c ? "yes" : "NO");
30470 - if (!c) return HANDLER_GO_ON;
30472 - buffer_free(c->server_name);
30473 - buffer_free(c->document_root);
30474 - buffer_free(c->fcgi_arg);
30475 - c->fcgi_offset = 0;
30480 - con->plugin_ctx[p->id] = NULL;
30481 return HANDLER_GO_ON;
30484 /* set configuration values */
30485 SERVER_FUNC(mod_mysql_vhost_set_defaults) {
30486 plugin_data *p = p_d;
30487 + mod_sql_vhost_core_plugin_data *core_config;
30492 - config_values_t cv[] = {
30493 - { "mysql-vhost.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
30494 - { "mysql-vhost.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
30495 - { "mysql-vhost.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
30496 - { "mysql-vhost.sock", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
30497 - { "mysql-vhost.sql", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
30498 - { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER },
30499 - { "mysql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER },
30500 - { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
30503 + /* our very own plugin storage, one entry for each conditional
30505 + * srv->config_context->used is the number of conditionals
30507 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
30510 + /* get the config of the core-plugin */
30511 + core_config = plugin_get_config(srv, CORE_PLUGIN);
30514 + /* walk through all conditionals and check for assignments */
30515 for (i = 0; i < srv->config_context->used; i++) {
30522 + /* get the config from the core plugin for this conditional-context */
30523 s = calloc(1, sizeof(plugin_config));
30524 - s->mydb = buffer_init();
30525 - s->myuser = buffer_init();
30526 - s->mypass = buffer_init();
30527 - s->mysock = buffer_init();
30528 - s->hostname = buffer_init();
30529 - s->port = 0; /* default port for mysql */
30530 - sel = buffer_init();
30533 + s->core = core_config->config_storage[i];
30537 s->mysql_pre = buffer_init();
30538 s->mysql_post = buffer_init();
30540 - cv[0].destination = s->mydb;
30541 - cv[1].destination = s->myuser;
30542 - cv[2].destination = s->mypass;
30543 - cv[3].destination = s->mysock;
30544 - cv[4].destination = sel;
30545 - cv[5].destination = s->hostname;
30546 - cv[6].destination = &(s->port);
30549 p->config_storage[i] = s;
30551 - if (config_insert_values_global(srv,
30552 - ((data_config *)srv->config_context->data[i])->value,
30553 - cv)) return HANDLER_ERROR;
30555 - s->mysql_pre = buffer_init();
30556 - s->mysql_post = buffer_init();
30559 + /* check if we are the plugin for this backend */
30560 + if (!buffer_is_equal_string(s->core->backend, CONST_STR_LEN("mysql"))) continue;
30562 + /* attach us to the core-plugin */
30563 + s->core->backend_data = p;
30564 + s->core->get_vhost = mod_mysql_vhost_get_vhost;
30566 + sel = buffer_init();
30567 + buffer_copy_string_buffer(sel, s->core->select_vhost);
30569 if (sel->used && (qmark = index(sel->ptr, '?'))) {
30571 buffer_copy_string(s->mysql_pre, sel->ptr);
30572 @@ -228,35 +145,38 @@
30574 buffer_copy_string_buffer(s->mysql_pre, sel);
30577 + buffer_free(sel);
30586 * - password, default: empty
30587 * - socket, default: mysql default
30588 * - hostname, if set overrides socket
30589 * - port, default: 3306
30593 /* all have to be set */
30594 - if (!(buffer_is_empty(s->myuser) ||
30595 - buffer_is_empty(s->mydb))) {
30596 + if (!(buffer_is_empty(s->core->user) ||
30597 + buffer_is_empty(s->core->db))) {
30602 if (NULL == (s->mysql = mysql_init(NULL))) {
30603 log_error_write(srv, __FILE__, __LINE__, "s", "mysql_init() failed, exiting...");
30606 return HANDLER_ERROR;
30608 -#define FOO(x) (s->x->used ? s->x->ptr : NULL)
30610 - if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass),
30611 - FOO(mydb), s->port, FOO(mysock), 0)) {
30612 +#define FOO(x) (s->core->x->used ? s->core->x->ptr : NULL)
30614 + s->mysql->free_me = 1;
30616 + if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(user), FOO(pass),
30617 + FOO(db), s->core->port, FOO(sock), 0)) {
30618 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(s->mysql));
30621 return HANDLER_ERROR;
30624 @@ -265,61 +185,47 @@
30625 /* otherwise we cannot be sure that mysql is fd i-1 */
30626 if (-1 == (fd = open("/dev/null", 0))) {
30628 - fcntl(fd-1, F_SETFD, FD_CLOEXEC);
30629 + fcntl(fd-1, F_SETFD, FD_CLOEXEC);
30638 return HANDLER_GO_ON;
30641 -#define PATCH(x) \
30642 - p->conf.x = s->x;
30643 static int mod_mysql_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
30646 plugin_config *s = p->config_storage[0];
30648 - PATCH(mysql_pre);
30649 - PATCH(mysql_post);
30655 + PATCH_OPTION(mysql_pre);
30656 + PATCH_OPTION(mysql_post);
30657 + PATCH_OPTION(mysql);
30659 /* skip the first, the global context */
30660 for (i = 1; i < srv->config_context->used; i++) {
30661 data_config *dc = (data_config *)srv->config_context->data[i];
30662 s = p->config_storage[i];
30665 /* condition didn't match */
30666 if (!config_check_cond(srv, con, dc)) continue;
30668 - /* merge config */
30669 - for (j = 0; j < dc->value->used; j++) {
30670 - data_unset *du = dc->value->data[j];
30672 - if (buffer_is_equal_string(du->key, CONST_STR_LEN("mysql-vhost.sql"))) {
30673 - PATCH(mysql_pre);
30674 - PATCH(mysql_post);
30681 + PATCH_OPTION(mysql);
30682 + PATCH_OPTION(mysql_pre);
30683 + PATCH_OPTION(mysql_post);
30693 -/* handle document root request */
30694 -CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
30696 + * get the vhost info from the database
30698 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost) {
30699 plugin_data *p = p_d;
30700 - plugin_connection_data *c;
30701 - stat_cache_entry *sce;
30705 @@ -332,13 +238,6 @@
30707 if (!p->conf.mysql) return HANDLER_GO_ON;
30709 - /* sets up connection data if not done yet */
30710 - c = mod_mysql_vhost_connection_data(srv, con, p_d);
30712 - /* check if cached this connection */
30713 - if (c->server_name->used && /* con->uri.authority->used && */
30714 - buffer_is_equal(c->server_name, con->uri.authority)) goto GO_ON;
30716 /* build and run SQL query */
30717 buffer_copy_string_buffer(p->tmp_buf, p->conf.mysql_pre);
30718 if (p->conf.mysql_post->used) {
30719 @@ -347,77 +246,43 @@
30721 if (mysql_query(p->conf.mysql, p->tmp_buf->ptr)) {
30722 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(p->conf.mysql));
30725 + mysql_free_result(result);
30726 + return HANDLER_GO_ON;
30728 result = mysql_store_result(p->conf.mysql);
30729 cols = mysql_num_fields(result);
30730 row = mysql_fetch_row(result);
30732 if (!row || cols < 1) {
30733 /* no such virtual host */
30734 mysql_free_result(result);
30735 return HANDLER_GO_ON;
30738 - /* sanity check that really is a directory */
30739 - buffer_copy_string(p->tmp_buf, row[0]);
30740 - BUFFER_APPEND_SLASH(p->tmp_buf);
30742 - if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
30743 - log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
30746 - if (!S_ISDIR(sce->st.st_mode)) {
30747 - log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->tmp_buf);
30750 + buffer_copy_string(docroot, row[0]);
30752 - /* cache the data */
30753 - buffer_copy_string_buffer(c->server_name, con->uri.authority);
30754 - buffer_copy_string_buffer(c->document_root, p->tmp_buf);
30756 - /* fcgi_offset and fcgi_arg are optional */
30757 - if (cols > 1 && row[1]) {
30758 - c->fcgi_offset = atoi(row[1]);
30760 - if (cols > 2 && row[2]) {
30761 - buffer_copy_string(c->fcgi_arg, row[2]);
30763 - c->fcgi_arg->used = 0;
30766 - c->fcgi_offset = c->fcgi_arg->used = 0;
30768 mysql_free_result(result);
30770 - /* fix virtual server and docroot */
30771 -GO_ON: buffer_copy_string_buffer(con->server_name, c->server_name);
30772 - buffer_copy_string_buffer(con->physical.doc_root, c->document_root);
30775 - log_error_write(srv, __FILE__, __LINE__, "sbbdb",
30776 - result ? "NOT CACHED" : "cached",
30777 - con->server_name, con->physical.doc_root,
30778 - c->fcgi_offset, c->fcgi_arg);
30780 - return HANDLER_GO_ON;
30782 -ERR500: if (result) mysql_free_result(result);
30783 - con->http_status = 500; /* Internal Error */
30784 - return HANDLER_FINISHED;
30785 + return HANDLER_GO_ON;
30788 /* this function is called at dlopen() time and inits the callbacks */
30789 int mod_mysql_vhost_plugin_init(plugin *p) {
30792 p->version = LIGHTTPD_VERSION_ID;
30793 p->name = buffer_init_string("mysql_vhost");
30795 p->init = mod_mysql_vhost_init;
30796 p->cleanup = mod_mysql_vhost_cleanup;
30797 - p->handle_request_done = mod_mysql_vhost_handle_connection_close;
30799 p->set_defaults = mod_mysql_vhost_set_defaults;
30800 - p->handle_docroot = mod_mysql_vhost_handle_docroot;
30802 + ds = data_string_init();
30803 + buffer_copy_string(ds->value, CORE_PLUGIN);
30804 + array_insert_unique(p->required_plugins, (data_unset *)ds);
30809 --- ../lighttpd-1.4.11/src/mod_proxy.c 2006-01-31 13:01:22.000000000 +0200
30810 +++ lighttpd-1.5.0/src/mod_proxy.c 2006-09-07 00:57:05.000000000 +0300
30812 #include <sys/types.h>
30814 -#include <unistd.h>
30817 #include <string.h>
30819 #include "keyvalue.h"
30822 -#include "http_chunk.h"
30823 #include "fdevent.h"
30824 #include "connections.h"
30825 #include "response.h"
30828 #include "inet_ntop_cache.h"
30830 +#include "network.h"
30832 +#include "http_resp.h"
30839 #include "sys-socket.h"
30840 +#include "sys-files.h"
30841 +#include "sys-strings.h"
30843 #define data_proxy data_fastcgi
30844 #define data_proxy_init data_fastcgi_init
30845 @@ -38,22 +41,25 @@
30846 #define PROXY_RETRY_TIMEOUT 60
30850 - * the proxy module is based on the fastcgi module
30853 + * the proxy module is based on the fastcgi module
30855 * 28.06.2004 Jan Kneschke The first release
30856 * 01.07.2004 Evgeny Rodichev Several bugfixes and cleanups
30857 * - co-ordinate up- and downstream flows correctly (proxy_demux_response
30858 * and proxy_handle_fdevent)
30859 * - correctly transfer upstream http_response_status;
30860 * - some unused structures removed.
30863 * TODO: - delay upstream read if write_queue is too large
30864 * (to prevent memory eating, like in apache). Shoud be
30866 * - persistent connection with upstream servers
30873 PROXY_BALANCE_UNSET,
30874 PROXY_BALANCE_FAIR,
30875 @@ -66,26 +72,33 @@
30878 proxy_balance_t balance;
30880 + array *last_used_backends; /* "extension" : last_used_backend */
30887 buffer *parse_response;
30888 buffer *balance_buf;
30893 + array *ignore_headers;
30895 plugin_config **config_storage;
30898 plugin_config conf;
30902 - PROXY_STATE_INIT,
30903 - PROXY_STATE_CONNECT,
30904 - PROXY_STATE_PREPARE_WRITE,
30905 - PROXY_STATE_WRITE,
30906 - PROXY_STATE_READ,
30907 - PROXY_STATE_ERROR
30909 + PROXY_STATE_INIT,
30910 + PROXY_STATE_CONNECT,
30911 + PROXY_STATE_PREPARE_WRITE,
30912 + PROXY_STATE_WRITE,
30913 + PROXY_STATE_RESPONSE_HEADER,
30914 + PROXY_STATE_RESPONSE_CONTENT,
30915 + PROXY_STATE_ERROR
30916 } proxy_connection_state_t;
30918 enum { PROXY_STDOUT, PROXY_END_REQUEST };
30919 @@ -93,19 +106,16 @@
30921 proxy_connection_state_t state;
30922 time_t state_timestamp;
30927 - buffer *response;
30928 - buffer *response_header;
30932 - int fd; /* fd to the proxy process */
30933 - int fde_ndx; /* index into the fd-event buffer */
30936 + iosocket *sock; /* fd to the proxy process */
30938 size_t path_info_offset; /* start of path_info in uri.path */
30941 connection *remote_conn; /* dump pointer */
30942 plugin_data *plugin_data; /* dump pointer */
30944 @@ -116,69 +126,89 @@
30946 static handler_ctx * handler_ctx_init() {
30947 handler_ctx * hctx;
30951 hctx = calloc(1, sizeof(*hctx));
30954 hctx->state = PROXY_STATE_INIT;
30957 - hctx->response = buffer_init();
30958 - hctx->response_header = buffer_init();
30960 hctx->wb = chunkqueue_init();
30961 + hctx->rb = chunkqueue_init();
30963 + hctx->sock = iosocket_init();
30966 - hctx->fde_ndx = -1;
30971 static void handler_ctx_free(handler_ctx *hctx) {
30972 - buffer_free(hctx->response);
30973 - buffer_free(hctx->response_header);
30974 chunkqueue_free(hctx->wb);
30976 + chunkqueue_free(hctx->rb);
30978 + iosocket_free(hctx->sock);
30983 INIT_FUNC(mod_proxy_init) {
30988 + char *hop2hop_headers[] = {
30995 p = calloc(1, sizeof(*p));
30997 - p->parse_response = buffer_init();
30999 p->balance_buf = buffer_init();
31001 + p->ignore_headers = array_init();
31002 + p->resp = http_response_init();
31004 + for (i = 0; hop2hop_headers[i]; i++) {
31007 + if (NULL == (ds = (data_string *)array_get_unused_element(p->ignore_headers, TYPE_STRING))) {
31008 + ds = data_string_init();
31011 + buffer_copy_string(ds->key, hop2hop_headers[i]);
31012 + buffer_copy_string(ds->value, hop2hop_headers[i]);
31013 + array_insert_unique(p->ignore_headers, (data_unset *)ds);
31020 FREE_FUNC(mod_proxy_free) {
31021 plugin_data *p = p_d;
31026 - buffer_free(p->parse_response);
31027 - buffer_free(p->balance_buf);
31029 if (p->config_storage) {
31031 for (i = 0; i < srv->config_context->used; i++) {
31032 plugin_config *s = p->config_storage[i];
31037 array_free(s->extensions);
31039 + array_free(s->last_used_backends);
31044 free(p->config_storage);
31048 + array_free(p->ignore_headers);
31049 + buffer_free(p->balance_buf);
31050 + http_response_free(p->resp);
31055 return HANDLER_GO_ON;
31058 @@ -186,37 +216,38 @@
31059 plugin_data *p = p_d;
31063 - config_values_t cv[] = {
31065 + config_values_t cv[] = {
31066 { "proxy.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
31067 { "proxy.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
31068 { "proxy.balance", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
31069 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
31073 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
31076 for (i = 0; i < srv->config_context->used; i++) {
31081 s = malloc(sizeof(plugin_config));
31082 - s->extensions = array_init();
31083 + s->extensions = array_init();
31084 + s->last_used_backends = array_init();
31088 cv[0].destination = s->extensions;
31089 cv[1].destination = &(s->debug);
31090 cv[2].destination = p->balance_buf;
31092 buffer_reset(p->balance_buf);
31095 p->config_storage[i] = s;
31096 ca = ((data_config *)srv->config_context->data[i])->value;
31099 if (0 != config_insert_values_global(srv, ca, cv)) {
31100 return HANDLER_ERROR;
31104 if (buffer_is_empty(p->balance_buf)) {
31105 s->balance = PROXY_BALANCE_FAIR;
31106 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) {
31107 @@ -226,99 +257,99 @@
31108 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("hash"))) {
31109 s->balance = PROXY_BALANCE_HASH;
31111 - log_error_write(srv, __FILE__, __LINE__, "sb",
31112 - "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
31113 + log_error_write(srv, __FILE__, __LINE__, "sb",
31114 + "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
31115 return HANDLER_ERROR;
31118 if (NULL != (du = array_get_element(ca, "proxy.server"))) {
31120 data_array *da = (data_array *)du;
31123 if (du->type != TYPE_ARRAY) {
31124 - log_error_write(srv, __FILE__, __LINE__, "sss",
31125 + log_error_write(srv, __FILE__, __LINE__, "sss",
31126 "unexpected type for key: ", "proxy.server", "array of strings");
31129 return HANDLER_ERROR;
31135 * proxy.server = ( "<ext>" => ...,
31140 for (j = 0; j < da->value->used; j++) {
31141 data_array *da_ext = (data_array *)da->value->data[j];
31145 if (da_ext->type != TYPE_ARRAY) {
31146 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
31147 - "unexpected type for key: ", "proxy.server",
31148 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
31149 + "unexpected type for key: ", "proxy.server",
31150 "[", da->value->data[j]->key, "](string)");
31153 return HANDLER_ERROR;
31157 - * proxy.server = ( "<ext>" =>
31158 - * ( "<host>" => ( ... ),
31161 + * proxy.server = ( "<ext>" =>
31162 + * ( "<host>" => ( ... ),
31163 * "<host>" => ( ... )
31170 for (n = 0; n < da_ext->value->used; n++) {
31171 data_array *da_host = (data_array *)da_ext->value->data[n];
31177 - config_values_t pcv[] = {
31179 + config_values_t pcv[] = {
31180 { "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
31181 { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
31182 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
31186 if (da_host->type != TYPE_ARRAY) {
31187 - log_error_write(srv, __FILE__, __LINE__, "ssSBS",
31188 - "unexpected type for key:",
31190 + log_error_write(srv, __FILE__, __LINE__, "ssSBS",
31191 + "unexpected type for key:",
31193 "[", da_ext->value->data[n]->key, "](string)");
31196 return HANDLER_ERROR;
31200 df = data_proxy_init();
31206 buffer_copy_string_buffer(df->key, da_host->key);
31209 pcv[0].destination = df->host;
31210 pcv[1].destination = &(df->port);
31213 if (0 != config_insert_values_internal(srv, da_host->value, pcv)) {
31214 return HANDLER_ERROR;
31218 if (buffer_is_empty(df->host)) {
31219 - log_error_write(srv, __FILE__, __LINE__, "sbbbs",
31220 - "missing key (string):",
31221 + log_error_write(srv, __FILE__, __LINE__, "sbbbs",
31222 + "missing key (string):",
31229 return HANDLER_ERROR;
31233 /* if extension already exists, take it */
31236 if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) {
31237 dfa = data_array_init();
31240 buffer_copy_string_buffer(dfa->key, da_ext->key);
31243 array_insert_unique(dfa->value, (data_unset *)df);
31244 array_insert_unique(s->extensions, (data_unset *)dfa);
31246 @@ -328,67 +359,76 @@
31252 return HANDLER_GO_ON;
31255 void proxy_connection_close(server *srv, handler_ctx *hctx) {
31260 if (NULL == hctx) return;
31263 p = hctx->plugin_data;
31264 con = hctx->remote_conn;
31266 - if (hctx->fd != -1) {
31267 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
31268 - fdevent_unregister(srv->ev, hctx->fd);
31271 + if (hctx->sock->fd != -1) {
31272 + fdevent_event_del(srv->ev, hctx->sock);
31273 + fdevent_unregister(srv->ev, hctx->sock);
31275 + close(hctx->sock->fd);
31280 handler_ctx_free(hctx);
31281 - con->plugin_ctx[p->id] = NULL;
31282 + con->plugin_ctx[p->id] = NULL;
31285 static int proxy_establish_connection(server *srv, handler_ctx *hctx) {
31286 struct sockaddr *proxy_addr;
31287 struct sockaddr_in proxy_addr_in;
31291 plugin_data *p = hctx->plugin_data;
31292 data_proxy *host= hctx->host;
31293 - int proxy_fd = hctx->fd;
31295 + int proxy_fd = hctx->sock->fd;
31297 memset(&proxy_addr, 0, sizeof(proxy_addr));
31300 proxy_addr_in.sin_family = AF_INET;
31301 proxy_addr_in.sin_addr.s_addr = inet_addr(host->host->ptr);
31302 proxy_addr_in.sin_port = htons(host->port);
31303 servlen = sizeof(proxy_addr_in);
31306 proxy_addr = (struct sockaddr *) &proxy_addr_in;
31309 if (-1 == connect(proxy_fd, proxy_addr, servlen)) {
31310 - if (errno == EINPROGRESS || errno == EALREADY) {
31312 + errno = WSAGetLastError();
31316 + case WSAEWOULDBLOCK:
31318 + case EINPROGRESS:
31320 if (p->conf.debug) {
31321 - log_error_write(srv, __FILE__, __LINE__, "sd",
31322 + log_error_write(srv, __FILE__, __LINE__, "sd",
31323 "connect delayed:", proxy_fd);
31330 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
31333 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
31334 "connect failed:", proxy_fd, strerror(errno), errno);
31340 + fprintf(stderr, "%s.%d: connected fd = %d\r\n", __FILE__, __LINE__, proxy_fd);
31341 if (p->conf.debug) {
31342 - log_error_write(srv, __FILE__, __LINE__, "sd",
31343 + log_error_write(srv, __FILE__, __LINE__, "sd",
31344 "connect succeeded: ", proxy_fd);
31347 @@ -396,51 +436,52 @@
31350 void proxy_set_header(connection *con, const char *key, const char *value) {
31351 - data_string *ds_dst;
31352 + data_string *ds_dst;
31354 + if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
31355 + ds_dst = data_string_init();
31358 - if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
31359 - ds_dst = data_string_init();
31362 - buffer_copy_string(ds_dst->key, key);
31363 - buffer_copy_string(ds_dst->value, value);
31364 - array_insert_unique(con->request.headers, (data_unset *)ds_dst);
31365 + buffer_copy_string(ds_dst->key, key);
31366 + buffer_copy_string(ds_dst->value, value);
31367 + array_insert_unique(con->request.headers, (data_unset *)ds_dst);
31370 void proxy_append_header(connection *con, const char *key, const char *value) {
31371 - data_string *ds_dst;
31372 + data_string *ds_dst;
31374 + if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
31375 + ds_dst = data_string_init();
31378 - if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
31379 - ds_dst = data_string_init();
31382 - buffer_copy_string(ds_dst->key, key);
31383 - buffer_append_string(ds_dst->value, value);
31384 - array_insert_unique(con->request.headers, (data_unset *)ds_dst);
31385 + buffer_copy_string(ds_dst->key, key);
31386 + buffer_append_string(ds_dst->value, value);
31387 + array_insert_unique(con->request.headers, (data_unset *)ds_dst);
31391 static int proxy_create_env(server *srv, handler_ctx *hctx) {
31395 connection *con = hctx->remote_conn;
31396 + plugin_data *p = hctx->plugin_data;
31402 b = chunkqueue_get_append_buffer(hctx->wb);
31406 buffer_copy_string(b, get_http_method_name(con->request.http_method));
31407 BUFFER_APPEND_STRING_CONST(b, " ");
31410 buffer_append_string_buffer(b, con->request.uri);
31411 BUFFER_APPEND_STRING_CONST(b, " HTTP/1.0\r\n");
31413 proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
31414 - /* http_host is NOT is just a pointer to a buffer
31415 + /* http_host is NOT is just a pointer to a buffer
31416 * which is NULL if it is not set */
31417 - if (con->request.http_host &&
31418 + if (con->request.http_host &&
31419 !buffer_is_empty(con->request.http_host)) {
31420 proxy_set_header(con, "X-Host", con->request.http_host->ptr);
31422 @@ -449,26 +490,27 @@
31423 /* request header */
31424 for (i = 0; i < con->request.headers->used; i++) {
31428 ds = (data_string *)con->request.headers->data[i];
31430 - if (ds->value->used && ds->key->used) {
31431 - if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
31433 - buffer_append_string_buffer(b, ds->key);
31434 - BUFFER_APPEND_STRING_CONST(b, ": ");
31435 - buffer_append_string_buffer(b, ds->value);
31436 - BUFFER_APPEND_STRING_CONST(b, "\r\n");
31439 + if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
31441 + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
31442 + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
31444 + buffer_append_string_buffer(b, ds->key);
31445 + BUFFER_APPEND_STRING_CONST(b, ": ");
31446 + buffer_append_string_buffer(b, ds->value);
31447 + BUFFER_APPEND_STRING_CONST(b, "\r\n");
31451 BUFFER_APPEND_STRING_CONST(b, "\r\n");
31454 hctx->wb->bytes_in += b->used - 1;
31458 if (con->request.content_length) {
31459 - chunkqueue *req_cq = con->request_content_queue;
31460 + chunkqueue *req_cq = con->recv;
31464 @@ -479,7 +521,7 @@
31466 /* we announce toWrite octects
31467 * now take all the request_content chunk that we need to fill this request
31471 switch (req_c->type) {
31473 @@ -507,223 +549,145 @@
31475 req_c->offset += weHave;
31476 req_cq->bytes_out += weHave;
31479 hctx->wb->bytes_in += weHave;
31496 static int proxy_set_state(server *srv, handler_ctx *hctx, proxy_connection_state_t state) {
31497 hctx->state = state;
31498 hctx->state_timestamp = srv->cur_ts;
31504 -static int proxy_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
31506 - int http_response_status = -1;
31510 - /* \r\n -> \0\0 */
31512 - buffer_copy_string_buffer(p->parse_response, in);
31514 - for (s = p->parse_response->ptr; NULL != (ns = strstr(s, "\r\n")); s = ns + 2) {
31515 - char *key, *value;
31523 - if (-1 == http_response_status) {
31524 - /* The first line of a Response message is the Status-Line */
31526 - for (key=s; *key && *key != ' '; key++);
31529 - http_response_status = (int) strtol(key, NULL, 10);
31530 - if (http_response_status <= 0) http_response_status = 502;
31532 - http_response_status = 502;
31535 - con->http_status = http_response_status;
31536 - con->parsed_response |= HTTP_STATUS;
31540 - if (NULL == (value = strchr(s, ':'))) {
31541 - /* now we expect: "<key>: <value>\n" */
31547 - key_len = value - key;
31551 - while (*value == ' ' || *value == '\t') value++;
31555 - switch(key_len) {
31557 - if (0 == strncasecmp(key, "Date", key_len)) {
31558 - con->parsed_response |= HTTP_DATE;
31562 - if (0 == strncasecmp(key, "Location", key_len)) {
31563 - con->parsed_response |= HTTP_LOCATION;
31567 - if (0 == strncasecmp(key, "Connection", key_len)) {
31572 - if (0 == strncasecmp(key, "Content-Length", key_len)) {
31573 - con->response.content_length = strtol(value, NULL, 10);
31574 - con->parsed_response |= HTTP_CONTENT_LENGTH;
31581 - if (copy_header) {
31582 - if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
31583 - ds = data_response_init();
31585 - buffer_copy_string_len(ds->key, key, key_len);
31586 - buffer_copy_string(ds->value, value);
31588 - array_insert_unique(con->response.headers, (data_unset *)ds);
31596 static int proxy_demux_response(server *srv, handler_ctx *hctx) {
31601 plugin_data *p = hctx->plugin_data;
31602 connection *con = hctx->remote_conn;
31603 - int proxy_fd = hctx->fd;
31605 - /* check how much we have to read */
31606 - if (ioctl(hctx->fd, FIONREAD, &b)) {
31607 - log_error_write(srv, __FILE__, __LINE__, "sd",
31608 - "ioctl failed: ",
31610 + chunkqueue *next_queue = NULL;
31613 + switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
31614 + case NETWORK_STATUS_SUCCESS:
31615 + /* we got content */
31617 + case NETWORK_STATUS_WAIT_FOR_EVENT:
31619 + case NETWORK_STATUS_CONNECTION_CLOSE:
31620 + /* we are done, get out of here */
31621 + con->send->is_closed = 1;
31623 + /* close the chunk-queue with a empty chunk */
31631 + /* looks like we got some content
31633 + * split off the header from the incoming stream
31636 - if (p->conf.debug) {
31637 - log_error_write(srv, __FILE__, __LINE__, "sd",
31638 - "proxy - have to read:", b);
31640 + if (hctx->state == PROXY_STATE_RESPONSE_HEADER) {
31642 + int have_content_length = 0;
31645 - if (hctx->response->used == 0) {
31646 - /* avoid too small buffer */
31647 - buffer_prepare_append(hctx->response, b + 1);
31648 - hctx->response->used = 1;
31650 - buffer_prepare_append(hctx->response, hctx->response->used + b);
31653 - if (-1 == (r = read(hctx->fd, hctx->response->ptr + hctx->response->used - 1, b))) {
31654 - log_error_write(srv, __FILE__, __LINE__, "sds",
31655 - "unexpected end-of-file (perhaps the proxy process died):",
31656 - proxy_fd, strerror(errno));
31660 - /* this should be catched by the b > 0 above */
31663 - hctx->response->used += r;
31664 - hctx->response->ptr[hctx->response->used - 1] = '\0';
31667 - log_error_write(srv, __FILE__, __LINE__, "sdsbs",
31668 - "demux: Response buffer len", hctx->response->used, ":", hctx->response, ":");
31670 + http_response_reset(p->resp);
31672 - if (0 == con->got_response) {
31673 - con->got_response = 1;
31674 - buffer_prepare_copy(hctx->response_header, 128);
31677 - if (0 == con->file_started) {
31680 - /* search for the \r\n\r\n in the string */
31681 - if (NULL != (c = buffer_search_string_len(hctx->response, "\r\n\r\n", 4))) {
31682 - size_t hlen = c - hctx->response->ptr + 4;
31683 - size_t blen = hctx->response->used - hlen - 1;
31686 - buffer_append_string_len(hctx->response_header, hctx->response->ptr, c - hctx->response->ptr + 4);
31688 - log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header);
31690 - /* parse the response header */
31691 - proxy_response_parse(srv, con, p, hctx->response_header);
31693 - /* enable chunked-transfer-encoding */
31694 - if (con->request.http_version == HTTP_VERSION_1_1 &&
31695 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
31696 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
31697 + /* the response header is not fully received yet,
31699 + * extract the http-response header from the rb-cq
31701 + switch (http_response_parse_cq(hctx->rb, p->resp)) {
31702 + case PARSE_ERROR:
31703 + /* parsing failed */
31705 + con->http_status = 502; /* Bad Gateway */
31707 + case PARSE_NEED_MORE:
31709 + case PARSE_SUCCESS:
31710 + con->http_status = p->resp->status;
31712 + chunkqueue_remove_finished_chunks(hctx->rb);
31714 + /* copy the http-headers */
31715 + for (i = 0; i < p->resp->headers->used; i++) {
31716 + const char *ign[] = { "Status", "Connection", NULL };
31720 + data_string *header = (data_string *)p->resp->headers->data[i];
31722 + /* some headers are ignored by default */
31723 + for (j = 0; ign[j]; j++) {
31724 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
31726 + if (ign[j]) continue;
31728 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
31729 + /* CGI/1.1 rev 03 - 7.2.1.2 */
31730 + if (con->http_status == 0) con->http_status = 302;
31731 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
31732 + have_content_length = 1;
31735 - con->file_started = 1;
31737 - http_chunk_append_mem(srv, con, c + 4, blen + 1);
31738 - joblist_append(srv, con);
31740 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
31741 + ds = data_response_init();
31743 - hctx->response->used = 0;
31744 + buffer_copy_string_buffer(ds->key, header->key);
31745 + buffer_copy_string_buffer(ds->value, header->value);
31747 + array_insert_unique(con->response.headers, (data_unset *)ds);
31750 - http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
31751 - joblist_append(srv, con);
31752 - hctx->response->used = 0;
31754 + con->file_started = 1;
31756 + hctx->state = PROXY_STATE_RESPONSE_CONTENT;
31761 - /* reading from upstream done */
31762 - con->file_finished = 1;
31764 - http_chunk_append_mem(srv, con, NULL, 0);
31765 - joblist_append(srv, con);
31772 + /* FIXME: pass the response-header to the other plugins to
31773 + * setup the filter-queue
31775 + * - use next-queue instead of con->write_queue
31778 + next_queue = con->send;
31780 + assert(hctx->state == PROXY_STATE_RESPONSE_CONTENT);
31782 + /* FIXME: if we have a content-length or chunked-encoding
31785 + * for now we wait for EOF on the socket */
31787 + /* copy the content to the next cq */
31788 + for (c = hctx->rb->first; c; c = c->next) {
31789 + chunkqueue_append_mem(con->send, c->mem->ptr + c->offset, c->mem->used - c->offset);
31791 + c->offset = c->mem->used - 1;
31794 + chunkqueue_remove_finished_chunks(hctx->rb);
31795 + joblist_append(srv, con);
31801 @@ -731,32 +695,32 @@
31802 data_proxy *host= hctx->host;
31803 plugin_data *p = hctx->plugin_data;
31804 connection *con = hctx->remote_conn;
31810 - (!host->host->used || !host->port)) return -1;
31814 + (!host->host->used || !host->port)) return -1;
31816 switch(hctx->state) {
31817 case PROXY_STATE_INIT:
31818 - if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
31819 + if (-1 == (hctx->sock->fd = socket(AF_INET, SOCK_STREAM, 0))) {
31820 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
31821 return HANDLER_ERROR;
31823 - hctx->fde_ndx = -1;
31825 + hctx->sock->fde_ndx = -1;
31829 - fdevent_register(srv->ev, hctx->fd, proxy_handle_fdevent, hctx);
31831 - if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
31833 + fdevent_register(srv->ev, hctx->sock, proxy_handle_fdevent, hctx);
31835 + if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
31836 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
31839 return HANDLER_ERROR;
31846 case PROXY_STATE_CONNECT:
31847 /* try to finish the connect() */
31848 if (hctx->state == PROXY_STATE_INIT) {
31849 @@ -764,16 +728,16 @@
31850 switch (proxy_establish_connection(srv, hctx)) {
31852 proxy_set_state(srv, hctx, PROXY_STATE_CONNECT);
31855 /* connection is in progress, wait for an event and call getsockopt() below */
31857 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
31860 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
31862 return HANDLER_WAIT_FOR_EVENT;
31864 /* if ECONNREFUSED choose another connection -> FIXME */
31865 - hctx->fde_ndx = -1;
31867 + hctx->sock->fde_ndx = -1;
31869 return HANDLER_ERROR;
31871 /* everything is ok, go on */
31872 @@ -782,152 +746,152 @@
31875 socklen_t socket_error_len = sizeof(socket_error);
31877 - /* we don't need it anymore */
31878 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
31880 + /* we don't need it anymore */
31881 + fdevent_event_del(srv->ev, hctx->sock);
31883 /* try to finish the connect() */
31884 - if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
31885 - log_error_write(srv, __FILE__, __LINE__, "ss",
31886 + if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
31887 + log_error_write(srv, __FILE__, __LINE__, "ss",
31888 "getsockopt failed:", strerror(errno));
31891 return HANDLER_ERROR;
31893 if (socket_error != 0) {
31894 log_error_write(srv, __FILE__, __LINE__, "ss",
31895 - "establishing connection failed:", strerror(socket_error),
31896 + "establishing connection failed:", strerror(socket_error),
31897 "port:", hctx->host->port);
31900 return HANDLER_ERROR;
31902 if (p->conf.debug) {
31903 - log_error_write(srv, __FILE__, __LINE__, "s", "proxy - connect - delayed success");
31904 + log_error_write(srv, __FILE__, __LINE__, "s", "proxy - connect - delayed success");
31909 proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);
31911 case PROXY_STATE_PREPARE_WRITE:
31912 proxy_create_env(srv, hctx);
31915 proxy_set_state(srv, hctx, PROXY_STATE_WRITE);
31919 case PROXY_STATE_WRITE:;
31920 - ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
31921 + ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
31923 chunkqueue_remove_finished_chunks(hctx->wb);
31926 - if (errno != EAGAIN &&
31927 - errno != EINTR) {
31928 - log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
31930 - return HANDLER_ERROR;
31932 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
31934 + case NETWORK_STATUS_FATAL_ERROR:
31935 + log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
31937 - return HANDLER_WAIT_FOR_EVENT;
31939 + return HANDLER_ERROR;
31940 + case NETWORK_STATUS_WAIT_FOR_EVENT:
31942 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
31944 + return HANDLER_WAIT_FOR_EVENT;
31947 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
31948 - proxy_set_state(srv, hctx, PROXY_STATE_READ);
31949 + proxy_set_state(srv, hctx, PROXY_STATE_RESPONSE_HEADER);
31951 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
31952 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
31953 + fdevent_event_del(srv->ev, hctx->sock);
31954 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
31956 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
31958 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
31960 return HANDLER_WAIT_FOR_EVENT;
31964 return HANDLER_WAIT_FOR_EVENT;
31965 - case PROXY_STATE_READ:
31966 + case PROXY_STATE_RESPONSE_CONTENT:
31967 + case PROXY_STATE_RESPONSE_HEADER:
31968 /* waiting for a response */
31970 return HANDLER_WAIT_FOR_EVENT;
31972 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
31973 return HANDLER_ERROR;
31977 return HANDLER_GO_ON;
31980 -#define PATCH(x) \
31981 - p->conf.x = s->x;
31982 static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data *p) {
31984 plugin_config *s = p->config_storage[0];
31986 - PATCH(extensions);
31991 + PATCH_OPTION(extensions);
31992 + PATCH_OPTION(debug);
31993 + PATCH_OPTION(balance);
31994 + PATCH_OPTION(last_used_backends);
31996 /* skip the first, the global context */
31997 for (i = 1; i < srv->config_context->used; i++) {
31998 data_config *dc = (data_config *)srv->config_context->data[i];
31999 s = p->config_storage[i];
32002 /* condition didn't match */
32003 if (!config_check_cond(srv, con, dc)) continue;
32007 for (j = 0; j < dc->value->used; j++) {
32008 data_unset *du = dc->value->data[j];
32011 if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.server"))) {
32012 - PATCH(extensions);
32013 + PATCH_OPTION(extensions);
32014 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.debug"))) {
32016 + PATCH_OPTION(debug);
32017 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.balance"))) {
32019 + PATCH_OPTION(balance);
32020 + PATCH_OPTION(last_used_backends);
32030 SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
32031 plugin_data *p = p_d;
32034 handler_ctx *hctx = con->plugin_ctx[p->id];
32038 if (NULL == hctx) return HANDLER_GO_ON;
32040 mod_proxy_patch_connection(srv, con, p);
32047 if (con->mode != p->id) return HANDLER_GO_ON;
32050 /* ok, create the request */
32051 switch(proxy_write_request(srv, hctx)) {
32052 case HANDLER_ERROR:
32053 - log_error_write(srv, __FILE__, __LINE__, "sbdd", "proxy-server disabled:",
32054 + log_error_write(srv, __FILE__, __LINE__, "sbdd", "proxy-server disabled:",
32061 /* disable this server */
32062 host->is_disabled = 1;
32063 host->disable_ts = srv->cur_ts;
32066 proxy_connection_close(srv, hctx);
32068 - /* reset the enviroment and restart the sub-request */
32070 + /* reset the enviroment and restart the sub-request */
32071 buffer_reset(con->physical.path);
32072 con->mode = DIRECT;
32074 joblist_append(srv, con);
32076 - /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
32077 - * and hope that the childs will be restarted
32079 + /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
32080 + * and hope that the childs will be restarted
32084 return HANDLER_WAIT_FOR_FD;
32085 @@ -938,7 +902,7 @@
32091 if (con->file_started == 1) {
32092 return HANDLER_FINISHED;
32094 @@ -951,13 +915,14 @@
32095 handler_ctx *hctx = ctx;
32096 connection *con = hctx->remote_conn;
32097 plugin_data *p = hctx->plugin_data;
32102 if ((revents & FDEVENT_IN) &&
32103 - hctx->state == PROXY_STATE_READ) {
32104 + (hctx->state == PROXY_STATE_RESPONSE_HEADER ||
32105 + hctx->state == PROXY_STATE_RESPONSE_CONTENT)) {
32107 if (p->conf.debug) {
32108 - log_error_write(srv, __FILE__, __LINE__, "sd",
32109 + log_error_write(srv, __FILE__, __LINE__, "sd",
32110 "proxy: fdevent-in", hctx->state);
32113 @@ -965,86 +930,87 @@
32117 + log_error_write(srv, __FILE__, __LINE__, "sd",
32118 + "proxy: request done", hctx->sock->fd);
32119 hctx->host->usage--;
32123 proxy_connection_close(srv, hctx);
32126 joblist_append(srv, con);
32127 return HANDLER_FINISHED;
32129 if (con->file_started == 0) {
32130 /* nothing has been send out yet, send a 500 */
32131 - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
32132 con->http_status = 500;
32133 con->mode = DIRECT;
32135 /* response might have been already started, kill the connection */
32136 connection_set_state(srv, con, CON_STATE_ERROR);
32140 joblist_append(srv, con);
32141 return HANDLER_FINISHED;
32146 if (revents & FDEVENT_OUT) {
32147 if (p->conf.debug) {
32148 - log_error_write(srv, __FILE__, __LINE__, "sd",
32149 + log_error_write(srv, __FILE__, __LINE__, "sd",
32150 "proxy: fdevent-out", hctx->state);
32153 if (hctx->state == PROXY_STATE_CONNECT ||
32154 hctx->state == PROXY_STATE_WRITE) {
32155 /* we are allowed to send something out
32158 * 1. in a unfinished connect() call
32159 * 2. in a unfinished write() call (long POST request)
32161 return mod_proxy_handle_subrequest(srv, con, p);
32163 - log_error_write(srv, __FILE__, __LINE__, "sd",
32164 + log_error_write(srv, __FILE__, __LINE__, "sd",
32165 "proxy: out", hctx->state);
32170 /* perhaps this issue is already handled */
32171 if (revents & FDEVENT_HUP) {
32172 if (p->conf.debug) {
32173 - log_error_write(srv, __FILE__, __LINE__, "sd",
32174 + log_error_write(srv, __FILE__, __LINE__, "sd",
32175 "proxy: fdevent-hup", hctx->state);
32179 if (hctx->state == PROXY_STATE_CONNECT) {
32180 /* connect() -> EINPROGRESS -> HUP */
32184 - * what is proxy is doing if it can't reach the next hop ?
32186 + * what is proxy is doing if it can't reach the next hop ?
32191 proxy_connection_close(srv, hctx);
32192 joblist_append(srv, con);
32195 con->http_status = 503;
32196 con->mode = DIRECT;
32199 return HANDLER_FINISHED;
32202 - con->file_finished = 1;
32203 + con->send->is_closed = 1;
32205 proxy_connection_close(srv, hctx);
32206 joblist_append(srv, con);
32207 } else if (revents & FDEVENT_ERR) {
32208 /* kill all connections to the proxy process */
32211 log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents);
32213 joblist_append(srv, con);
32214 proxy_connection_close(srv, hctx);
32218 return HANDLER_FINISHED;
32221 @@ -1058,44 +1024,48 @@
32223 data_array *extension = NULL;
32224 size_t path_info_offset;
32226 + data_integer *last_used_backend;
32227 + data_proxy *host = NULL;
32228 + handler_ctx *hctx = NULL;
32230 + array *backends = NULL;
32232 /* Possibly, we processed already this request */
32233 if (con->file_started == 1) return HANDLER_GO_ON;
32236 mod_proxy_patch_connection(srv, con, p);
32239 fn = con->uri.path;
32241 if (fn->used == 0) {
32242 return HANDLER_ERROR;
32246 s_len = fn->used - 1;
32250 path_info_offset = 0;
32252 - if (p->conf.debug) {
32253 + if (p->conf.debug) {
32254 log_error_write(srv, __FILE__, __LINE__, "s", "proxy - start");
32257 /* check if extension matches */
32258 for (k = 0; k < p->conf.extensions->used; k++) {
32262 extension = (data_array *)p->conf.extensions->data[k];
32265 if (extension->key->used == 0) continue;
32268 ct_len = extension->key->used - 1;
32271 if (s_len < ct_len) continue;
32274 /* check extension in the form "/proxy_pattern" */
32275 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
32276 if (s_len > ct_len + 1) {
32280 if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) {
32281 path_info_offset = pi_offset - fn->ptr;
32283 @@ -1106,12 +1076,14 @@
32289 if (k == p->conf.extensions->used) {
32290 return HANDLER_GO_ON;
32293 - if (p->conf.debug) {
32294 + backends = extension->value;
32296 + if (p->conf.debug) {
32297 log_error_write(srv, __FILE__, __LINE__, "s", "proxy - ext found");
32300 @@ -1120,34 +1092,34 @@
32301 /* hash balancing */
32303 if (p->conf.debug) {
32304 - log_error_write(srv, __FILE__, __LINE__, "sd",
32305 - "proxy - used hash balancing, hosts:", extension->value->used);
32306 + log_error_write(srv, __FILE__, __LINE__, "sd",
32307 + "proxy - used hash balancing, hosts:", backends->used);
32310 - for (k = 0, ndx = -1, last_max = ULONG_MAX; k < extension->value->used; k++) {
32311 - data_proxy *host = (data_proxy *)extension->value->data[k];
32312 + for (k = 0, ndx = -1, last_max = ULONG_MAX; k < backends->used; k++) {
32313 unsigned long cur_max;
32315 - if (host->is_disabled) continue;
32317 + data_proxy *cur = (data_proxy *)backends->data[k];
32319 + if (cur->is_disabled) continue;
32321 cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
32322 - generate_crc32c(CONST_BUF_LEN(host->host)) + /* we can cache this */
32323 + generate_crc32c(CONST_BUF_LEN(cur->host)) + /* we can cache this */
32324 generate_crc32c(CONST_BUF_LEN(con->uri.authority));
32327 if (p->conf.debug) {
32328 - log_error_write(srv, __FILE__, __LINE__, "sbbbd",
32329 + log_error_write(srv, __FILE__, __LINE__, "sbbbd",
32330 "proxy - election:",
32334 con->uri.authority,
32338 - if ((last_max == ULONG_MAX) || /* first round */
32339 - (cur_max > last_max)) {
32340 + if (host == NULL || (cur_max > last_max)) {
32341 last_max = cur_max;
32348 @@ -1155,19 +1127,20 @@
32349 case PROXY_BALANCE_FAIR:
32350 /* fair balancing */
32351 if (p->conf.debug) {
32352 - log_error_write(srv, __FILE__, __LINE__, "s",
32353 + log_error_write(srv, __FILE__, __LINE__, "s",
32354 "proxy - used fair balancing");
32357 - for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
32358 - data_proxy *host = (data_proxy *)extension->value->data[k];
32360 - if (host->is_disabled) continue;
32362 - if (host->usage < max_usage) {
32363 - max_usage = host->usage;
32366 + /* try to find the host with the lowest load */
32367 + for (k = 0, max_usage = 0; k < backends->used; k++) {
32368 + data_proxy *cur = (data_proxy *)backends->data[k];
32370 + if (cur->is_disabled) continue;
32372 + if (NULL == host || cur->usage < max_usage) {
32373 + max_usage = cur->usage;
32379 @@ -1175,89 +1148,100 @@
32380 case PROXY_BALANCE_RR:
32382 if (p->conf.debug) {
32383 - log_error_write(srv, __FILE__, __LINE__, "s",
32384 + log_error_write(srv, __FILE__, __LINE__, "s",
32385 "proxy - used round-robin balancing");
32388 /* just to be sure */
32389 - assert(extension->value->used < INT_MAX);
32391 - for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
32392 - data_proxy *host = (data_proxy *)extension->value->data[k];
32394 - if (host->is_disabled) continue;
32396 - /* first usable ndx */
32397 - if (max_usage == INT_MAX) {
32400 + assert(backends->used < INT_MAX);
32402 - /* get next ndx */
32403 - if ((int)k > host->last_used_ndx) {
32405 - host->last_used_ndx = k;
32406 + /* send each request to another host:
32410 + * if we have three hosts it is
32412 + * 1 .. 2 .. 3 .. 1 .. 2 .. 3
32418 + /* walk through the list */
32419 + last_used_backend = (data_integer *)array_get_element(p->conf.last_used_backends, extension->key->ptr);
32421 + if (NULL == last_used_backend) {
32422 + last_used_backend = data_integer_init();
32424 + buffer_copy_string_buffer(last_used_backend->key, extension->key);
32425 + last_used_backend->value = 0;
32427 + array_insert_unique(p->conf.last_used_backends, (data_unset *)last_used_backend);
32430 + /* scan all but the last host to see if they are up
32431 + * take the first running host */
32432 + for (k = last_used_backend->value + 1; (int)(k % backends->used) != last_used_backend->value; k++) {
32433 + data_proxy *cur = (data_proxy *)backends->data[k % backends->used];
32435 + if (cur->is_disabled) continue;
32439 + last_used_backend->value = k;
32444 - /* didn't found a higher id, wrap to the start */
32445 - if (ndx != -1 && max_usage != INT_MAX) {
32448 + if (NULL == host) {
32449 + /* we found nothing better, fallback to the last used backend
32450 + * and check if it is still up */
32451 + host = (data_proxy *)backends->data[last_used_backend->value];
32453 + if (host->is_disabled) host = NULL;
32461 - /* found a server */
32463 - data_proxy *host = (data_proxy *)extension->value->data[ndx];
32466 - * if check-local is disabled, use the uri.path handler
32470 - /* init handler-context */
32471 - handler_ctx *hctx;
32472 - hctx = handler_ctx_init();
32474 - hctx->path_info_offset = path_info_offset;
32475 - hctx->remote_conn = con;
32476 - hctx->plugin_data = p;
32477 - hctx->host = host;
32479 - con->plugin_ctx[p->id] = hctx;
32483 - con->mode = p->id;
32485 - if (p->conf.debug) {
32486 - log_error_write(srv, __FILE__, __LINE__, "sbd",
32487 - "proxy - found a host",
32488 - host->host, host->port);
32491 - return HANDLER_GO_ON;
32493 - /* no handler found */
32494 + /* we havn't found a host */
32495 + if (NULL == host) {
32496 con->http_status = 500;
32498 - log_error_write(srv, __FILE__, __LINE__, "sb",
32499 - "no proxy-handler found for:",
32501 + log_error_write(srv, __FILE__, __LINE__, "sb",
32502 + "no proxy-handler found for:",
32506 return HANDLER_FINISHED;
32509 + /* init handler-context */
32510 + hctx = handler_ctx_init();
32512 + hctx->path_info_offset = path_info_offset;
32513 + hctx->remote_conn = con;
32514 + hctx->plugin_data = p;
32515 + hctx->host = host;
32517 + con->plugin_ctx[p->id] = hctx;
32521 + /* we handle this request */
32522 + con->mode = p->id;
32524 + if (p->conf.debug) {
32525 + log_error_write(srv, __FILE__, __LINE__, "sbd",
32526 + "proxy - found a host",
32527 + host->host, host->port);
32530 return HANDLER_GO_ON;
32533 static handler_t mod_proxy_connection_close_callback(server *srv, connection *con, void *p_d) {
32534 plugin_data *p = p_d;
32537 proxy_connection_close(srv, con->plugin_ctx[p->id]);
32539 return HANDLER_GO_ON;
32540 @@ -1276,11 +1260,11 @@
32542 for (i = 0; i < srv->config_context->used; i++) {
32543 plugin_config *s = p->config_storage[i];
32545 - if (!s) continue;
32547 + if (!s) continue;
32549 /* get the extensions for all configs */
32552 for (k = 0; k < s->extensions->used; k++) {
32553 data_array *extension = (data_array *)s->extensions->data[k];
32555 @@ -1290,8 +1274,8 @@
32557 if (!host->is_disabled ||
32558 srv->cur_ts - host->disable_ts < 5) continue;
32560 - log_error_write(srv, __FILE__, __LINE__, "sbd",
32562 + log_error_write(srv, __FILE__, __LINE__, "sbd",
32563 "proxy - re-enabled:",
32564 host->host, host->port);
32566 @@ -1315,10 +1299,10 @@
32567 p->connection_reset = mod_proxy_connection_close_callback; /* end of req-resp cycle */
32568 p->handle_connection_close = mod_proxy_connection_close_callback; /* end of client connection */
32569 p->handle_uri_clean = mod_proxy_check_extension;
32570 - p->handle_subrequest = mod_proxy_handle_subrequest;
32571 + p->handle_start_backend = mod_proxy_handle_subrequest;
32572 p->handle_trigger = mod_proxy_trigger;
32580 --- ../lighttpd-1.4.11/src/mod_proxy_backend_fastcgi.c 1970-01-01 03:00:00.000000000 +0300
32581 +++ lighttpd-1.5.0/src/mod_proxy_backend_fastcgi.c 2006-09-07 00:57:05.000000000 +0300
32583 +#include <stdlib.h>
32584 +#include <string.h>
32585 +#include <assert.h>
32587 +#include "inet_ntop_cache.h"
32588 +#include "mod_proxy_core.h"
32589 +#include "buffer.h"
32591 +#include "fastcgi.h"
32593 +int proxy_fastcgi_get_env_fastcgi(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
32598 + server_socket *srv_sock = con->srv_socket;
32600 + char b2[INET6_ADDRSTRLEN + 1];
32603 + sock_addr our_addr;
32604 + socklen_t our_addr_len;
32606 + proxy_set_header(sess->env_headers, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
32608 + if (con->server_name->used) {
32609 + proxy_set_header(sess->env_headers, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
32612 + s = inet_ntop(srv_sock->addr.plain.sa_family,
32613 + srv_sock->addr.plain.sa_family == AF_INET6 ?
32614 + (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
32615 + (const void *) &(srv_sock->addr.ipv4.sin_addr),
32616 + b2, sizeof(b2)-1);
32618 + s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
32620 + proxy_set_header(sess->env_headers, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
32623 + proxy_set_header(sess->env_headers, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
32627 + ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
32629 + ntohs(srv_sock->addr.ipv4.sin_port)
32633 + proxy_set_header(sess->env_headers, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
32635 + /* get the server-side of the connection to the client */
32636 + our_addr_len = sizeof(our_addr);
32638 + if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
32639 + s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
32641 + s = inet_ntop_cache_get_ip(srv, &(our_addr));
32643 + proxy_set_header(sess->env_headers, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
32647 + ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
32649 + ntohs(con->dst_addr.ipv4.sin_port)
32653 + proxy_set_header(sess->env_headers, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
32655 + s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
32656 + proxy_set_header(sess->env_headers, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
32658 + if (!buffer_is_empty(con->authed_user)) {
32659 + proxy_set_header(sess->env_headers, CONST_STR_LEN("REMOTE_USER"),
32660 + CONST_BUF_LEN(con->authed_user));
32663 + if (con->request.content_length > 0) {
32664 + /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
32666 + /* request.content_length < SSIZE_MAX, see request.c */
32667 + ltostr(buf, con->request.content_length);
32668 + proxy_set_header(sess->env_headers, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
32673 + * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
32674 + * http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html
32675 + * (6.1.14, 6.1.6, 6.1.7)
32676 + * For AUTHORIZER mode these headers should be omitted.
32679 + proxy_set_header(sess->env_headers, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
32681 + if (!buffer_is_empty(con->request.pathinfo)) {
32682 + proxy_set_header(sess->env_headers, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
32684 + /* PATH_TRANSLATED is only defined if PATH_INFO is set */
32686 + buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
32687 + buffer_append_string_buffer(p->tmp_buf, con->request.pathinfo);
32688 + proxy_set_header(sess->env_headers, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->tmp_buf));
32690 + proxy_set_header(sess->env_headers, CONST_STR_LEN("PATH_INFO"), CONST_STR_LEN(""));
32694 + * SCRIPT_FILENAME and DOCUMENT_ROOT for php. The PHP manual
32695 + * http://www.php.net/manual/en/reserved.variables.php
32696 + * treatment of PATH_TRANSLATED is different from the one of CGI specs.
32697 + * TODO: this code should be checked against cgi.fix_pathinfo php
32702 + proxy_set_header(sess->env_headers, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
32703 + proxy_set_header(sess->env_headers, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
32706 + proxy_set_header(sess->env_headers, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
32708 + if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
32709 + proxy_set_header(sess->env_headers, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri));
32711 + if (!buffer_is_empty(con->uri.query)) {
32712 + proxy_set_header(sess->env_headers, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
32714 + proxy_set_header(sess->env_headers, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
32717 + s = get_http_method_name(con->request.http_method);
32718 + proxy_set_header(sess->env_headers, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
32719 + proxy_set_header(sess->env_headers, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
32720 + s = get_http_version_name(con->request.http_version);
32721 + proxy_set_header(sess->env_headers, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
32723 +#ifdef USE_OPENSSL
32724 + if (srv_sock->is_ssl) {
32725 + proxy_set_header(sess->env_headers, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
32733 + * transform the HTTP-Request headers into CGI notation
32735 +int proxy_fastcgi_get_env_request(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
32737 + /* the request header got already copied into the sess->request_headers for us
32738 + * no extra filter is needed
32740 + * prepend a HTTP_ and uppercase the keys
32742 + for (i = 0; i < sess->request_headers->used; i++) {
32746 + ds = (data_string *)sess->request_headers->data[i];
32748 + buffer_reset(p->tmp_buf);
32750 + if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
32751 + BUFFER_COPY_STRING_CONST(p->tmp_buf, "HTTP_");
32752 + p->tmp_buf->used--;
32755 + buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
32756 + for (j = 0; j < ds->key->used - 1; j++) {
32758 + if (light_isalpha(ds->key->ptr[j])) {
32760 + c = ds->key->ptr[j] & ~32;
32761 + } else if (light_isdigit(ds->key->ptr[j])) {
32763 + c = ds->key->ptr[j];
32765 + p->tmp_buf->ptr[p->tmp_buf->used++] = c;
32767 + p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
32769 + proxy_set_header(sess->env_headers, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
32777 + * add a key-value pair to the fastcgi-buffer
32780 +static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
32783 + if (!key || !val) return -1;
32785 + len = key_len + val_len;
32787 + len += key_len > 127 ? 4 : 1;
32788 + len += val_len > 127 ? 4 : 1;
32790 + buffer_prepare_append(env, len);
32792 + if (key_len > 127) {
32793 + env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80;
32794 + env->ptr[env->used++] = (key_len >> 16) & 0xff;
32795 + env->ptr[env->used++] = (key_len >> 8) & 0xff;
32796 + env->ptr[env->used++] = (key_len >> 0) & 0xff;
32798 + env->ptr[env->used++] = (key_len >> 0) & 0xff;
32801 + if (val_len > 127) {
32802 + env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80;
32803 + env->ptr[env->used++] = (val_len >> 16) & 0xff;
32804 + env->ptr[env->used++] = (val_len >> 8) & 0xff;
32805 + env->ptr[env->used++] = (val_len >> 0) & 0xff;
32807 + env->ptr[env->used++] = (val_len >> 0) & 0xff;
32810 + memcpy(env->ptr + env->used, key, key_len);
32811 + env->used += key_len;
32812 + memcpy(env->ptr + env->used, val, val_len);
32813 + env->used += val_len;
32819 + * init the FCGI_header
32821 +static int fcgi_header(FCGI_Header * header, unsigned char type, size_t request_id, int contentLength, unsigned char paddingLength) {
32822 + header->version = FCGI_VERSION_1;
32823 + header->type = type;
32824 + header->requestIdB0 = request_id & 0xff;
32825 + header->requestIdB1 = (request_id >> 8) & 0xff;
32826 + header->contentLengthB0 = contentLength & 0xff;
32827 + header->contentLengthB1 = (contentLength >> 8) & 0xff;
32828 + header->paddingLength = paddingLength;
32829 + header->reserved = 0;
32835 +int proxy_fastcgi_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *out) {
32836 + buffer *b, *packet;
32838 + FCGI_BeginRequestRecord beginRecord;
32839 + FCGI_Header header;
32840 + int request_id = 1;
32842 + b = chunkqueue_get_append_buffer(out);
32843 + /* send FCGI_BEGIN_REQUEST */
32845 + fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, FCGI_NULL_REQUEST_ID, sizeof(beginRecord.body), 0);
32846 + beginRecord.body.roleB0 = FCGI_RESPONDER;
32847 + beginRecord.body.roleB1 = 0;
32848 + beginRecord.body.flags = 0;
32849 + memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
32851 + buffer_copy_string_len(b, (const char *)&beginRecord, sizeof(beginRecord));
32852 + out->bytes_in += sizeof(beginRecord);
32854 + /* send FCGI_PARAMS */
32855 + b = chunkqueue_get_append_buffer(out);
32856 + buffer_prepare_copy(b, 1024);
32858 + /* fill the sess->env_headers */
32859 + array_reset(sess->env_headers);
32860 + proxy_fastcgi_get_env_request(srv, con, p, sess);
32861 + proxy_fastcgi_get_env_fastcgi(srv, con, p, sess);
32863 + packet = buffer_init();
32865 + for (i = 0; i < sess->env_headers->used; i++) {
32868 + ds = (data_string *)sess->env_headers->data[i];
32869 + fcgi_env_add(packet, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
32872 + fcgi_header(&(header), FCGI_PARAMS, FCGI_NULL_REQUEST_ID, packet->used, 0);
32873 + buffer_append_memory(b, (const char *)&header, sizeof(header));
32874 + buffer_append_memory(b, (const char *)packet->ptr, packet->used);
32875 + out->bytes_in += sizeof(header);
32876 + out->bytes_in += packet->used - 1;
32878 + buffer_free(packet);
32880 + fcgi_header(&(header), FCGI_PARAMS, FCGI_NULL_REQUEST_ID, 0, 0);
32881 + buffer_append_memory(b, (const char *)&header, sizeof(header));
32882 + out->bytes_in += sizeof(header);
32893 + size_t request_id;
32894 +} fastcgi_response_packet;
32896 +int proxy_fastcgi_stream_decoder(server *srv, proxy_session *sess, chunkqueue *raw, chunkqueue *decoded) {
32898 + size_t offset = 0;
32899 + size_t toread = 0;
32900 + FCGI_Header *header;
32901 + fastcgi_response_packet packet;
32904 + if (!raw->first) return 0;
32906 + packet.b = buffer_init();
32909 + packet.padding = 0;
32910 + packet.request_id = 0;
32912 + /* get at least the FastCGI header */
32913 + for (c = raw->first; c; c = c->next) {
32914 + if (packet.b->used == 0) {
32915 + buffer_copy_string_len(packet.b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
32917 + buffer_append_string_len(packet.b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
32920 + if (packet.b->used >= sizeof(*header) + 1) break;
32923 + if ((packet.b->used == 0) ||
32924 + (packet.b->used - 1 < sizeof(FCGI_Header))) {
32926 + buffer_free(packet.b);
32928 + ERROR("%s", "FastCGI: header too small");
32932 + /* we have at least a header, now check how much me have to fetch */
32933 + header = (FCGI_Header *)(packet.b->ptr);
32935 + packet.len = (header->contentLengthB0 | (header->contentLengthB1 << 8)) + header->paddingLength;
32936 + packet.request_id = (header->requestIdB0 | (header->requestIdB1 << 8));
32937 + packet.type = header->type;
32938 + packet.padding = header->paddingLength;
32940 + /* the first bytes in packet->b are the header */
32941 + offset = sizeof(*header);
32943 + buffer_copy_string(packet.b, "");
32945 + if (packet.len) {
32946 + /* copy the content */
32947 + for (; c && (packet.b->used < packet.len + 1); c = c->next) {
32948 + size_t weWant = packet.len - (packet.b->used - 1);
32949 + size_t weHave = c->mem->used - c->offset - offset - 1;
32951 + if (weHave > weWant) weHave = weWant;
32953 + buffer_append_string_len(packet.b, c->mem->ptr + c->offset + offset, weHave);
32955 + /* we only skipped the first 8 bytes as they are the fcgi header */
32959 + if (packet.b->used < packet.len + 1) {
32960 + /* we didn't got the full packet */
32962 + buffer_free(packet.b);
32964 + TRACE("%s", "need more");
32969 + packet.b->used -= packet.padding;
32970 + packet.b->ptr[packet.b->used - 1] = '\0';
32973 + /* tag the chunks as read */
32974 + toread = packet.len + sizeof(FCGI_Header);
32975 + for (c = raw->first; c && toread; c = c->next) {
32976 + if (c->mem->used - c->offset - 1 <= toread) {
32977 + /* we read this whole buffer, move it to unused */
32978 + toread -= c->mem->used - c->offset - 1;
32979 + c->offset = c->mem->used - 1; /* everthing has been written */
32981 + c->offset += toread;
32986 + chunkqueue_remove_finished_chunks(raw);
32988 + /* we are still here ? */
32990 + switch (packet.type) {
32991 + case FCGI_STDOUT:
32992 + b = chunkqueue_get_append_buffer(decoded);
32993 + buffer_copy_string_buffer(b, packet.b);
32994 + buffer_free(packet.b);
32996 + case FCGI_STDERR:
32997 + if (!buffer_is_empty(packet.b)) {
32998 + TRACE("(fastcgi-stderr) %s", BUF_STR(packet.b));
33000 + buffer_free(packet.b);
33002 + case FCGI_END_REQUEST:
33003 + buffer_free(packet.b);
33006 + buffer_free(packet.b);
33008 + TRACE("unknown packet.type: %d", packet.type);
33014 + * transform the content-stream into a valid HTTP-content-stream
33016 + * as we don't apply chunked-encoding here, pass it on AS IS
33018 +int proxy_fastcgi_stream_encoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out) {
33021 + FCGI_Header header;
33023 + /* there is nothing that we have to send out anymore */
33024 + for (c = in->first; in->bytes_out < in->bytes_in; ) {
33025 + off_t weWant = in->bytes_in - in->bytes_out > FCGI_MAX_LENGTH ? FCGI_MAX_LENGTH : in->bytes_in - in->bytes_out;
33026 + off_t weHave = 0;
33028 + /* we announce toWrite octects
33029 + * now take all the request_content chunk that we need to fill this request
33031 + b = chunkqueue_get_append_buffer(out);
33032 + fcgi_header(&(header), FCGI_STDIN, FCGI_NULL_REQUEST_ID, weWant, 0);
33033 + buffer_copy_memory(b, (const char *)&header, sizeof(header) + 1);
33034 + out->bytes_in += sizeof(header);
33036 + switch (c->type) {
33038 + weHave = c->file.length - c->offset;
33040 + if (weHave > weWant) weHave = weWant;
33042 + chunkqueue_append_file(out, c->file.name, c->offset, weHave);
33044 + c->offset += weHave;
33045 + in->bytes_out += weHave;
33047 + out->bytes_in += weHave;
33049 + /* steal the tempfile
33051 + * This is tricky:
33052 + * - we reference the tempfile from the in-queue several times
33053 + * if the chunk is larger than FCGI_MAX_LENGTH
33054 + * - we can't simply cleanup the in-queue as soon as possible
33055 + * as it would remove the tempfiles
33056 + * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last
33057 + * referencing chunk of the fastcgi-write-queue
33061 + if (c->offset == c->file.length) {
33064 + out_c = out->last;
33066 + /* the last of the out-queue should be a FILE_CHUNK (we just created it)
33067 + * and the incoming side should have given use a temp-file-chunk */
33068 + assert(out_c->type == FILE_CHUNK);
33069 + assert(c->file.is_temp == 1);
33071 + out_c->file.is_temp = 1;
33072 + c->file.is_temp = 0;
33079 + /* append to the buffer */
33080 + weHave = c->mem->used - 1 - c->offset;
33082 + if (weHave > weWant) weHave = weWant;
33084 + b = chunkqueue_get_append_buffer(out);
33085 + buffer_append_memory(b, c->mem->ptr + c->offset, weHave);
33086 + b->used++; /* add virtual \0 */
33088 + c->offset += weHave;
33089 + in->bytes_out += weHave;
33091 + out->bytes_in += weHave;
33093 + if (c->offset == c->mem->used - 1) {
33103 + if (in->bytes_in == in->bytes_out && in->is_closed && !out->is_closed) {
33104 + /* send the closing packet */
33105 + b = chunkqueue_get_append_buffer(out);
33106 + /* terminate STDIN */
33107 + fcgi_header(&(header), FCGI_STDIN, FCGI_NULL_REQUEST_ID, 0, 0);
33108 + buffer_copy_memory(b, (const char *)&header, sizeof(header) + 1);
33110 + out->bytes_in += sizeof(header);
33111 + out->is_closed = 1;
33119 + * parse the response header
33121 + * NOTE: this can be used by all backends as they all send a HTTP-Response a clean block
33122 + * - fastcgi needs some decoding for the protocol
33124 +parse_status_t proxy_fastcgi_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
33125 + int have_content_length = 0;
33129 + http_response_reset(p->resp);
33131 + /* decode the whole packet stream */
33133 + old_len = chunkqueue_length(sess->recv);
33134 + /* decode the packet */
33135 + switch (proxy_fastcgi_stream_decoder(srv, sess, cq, sess->recv)) {
33137 + /* STDERR + STDOUT */
33140 + /* the FIN packet was catched, why ever */
33141 + return PARSE_ERROR;
33143 + return PARSE_ERROR;
33145 + } while (chunkqueue_length(sess->recv) == old_len);
33147 + switch (http_response_parse_cq(sess->recv, p->resp)) {
33148 + case PARSE_ERROR:
33149 + /* parsing failed */
33151 + return PARSE_ERROR;
33152 + case PARSE_NEED_MORE:
33153 + return PARSE_NEED_MORE;
33154 + case PARSE_SUCCESS:
33155 + con->http_status = p->resp->status;
33157 + chunkqueue_remove_finished_chunks(cq);
33159 + sess->content_length = -1;
33161 + /* copy the http-headers */
33162 + for (i = 0; i < p->resp->headers->used; i++) {
33163 + const char *ign[] = { "Status", "Connection", NULL };
33167 + data_string *header = (data_string *)p->resp->headers->data[i];
33169 + /* some headers are ignored by default */
33170 + for (j = 0; ign[j]; j++) {
33171 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
33173 + if (ign[j]) continue;
33175 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
33176 + /* CGI/1.1 rev 03 - 7.2.1.2 */
33177 + if (con->http_status == 0) con->http_status = 302;
33178 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
33179 + have_content_length = 1;
33181 + sess->content_length = strtol(header->value->ptr, NULL, 10);
33183 + if (sess->content_length < 0) {
33184 + return PARSE_ERROR;
33186 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Transfer-Encoding"))) {
33187 + if (strstr(header->value->ptr, "chunked")) {
33188 + sess->is_chunked = 1;
33190 + /* ignore the header */
33194 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
33195 + ds = data_response_init();
33199 + buffer_copy_string_buffer(ds->key, header->key);
33201 + for (k = 0; k < p->conf.response_rewrites->used; k++) {
33202 + proxy_rewrite *rw = p->conf.response_rewrites->ptr[k];
33204 + if (buffer_is_equal(rw->header, header->key)) {
33207 + if ((ret = pcre_replace(rw->regex, rw->replace, header->value, p->replace_buf)) < 0) {
33209 + case PCRE_ERROR_NOMATCH:
33210 + /* hmm, ok. no problem */
33211 + buffer_append_string_buffer(ds->value, header->value);
33214 + TRACE("oops, pcre_replace failed with: %d", ret);
33218 + buffer_append_string_buffer(ds->value, p->replace_buf);
33225 + if (k == p->conf.response_rewrites->used) {
33226 + buffer_copy_string_buffer(ds->value, header->value);
33229 + array_insert_unique(con->response.headers, (data_unset *)ds);
33235 + return PARSE_SUCCESS; /* we have a full header */
33239 --- ../lighttpd-1.4.11/src/mod_proxy_backend_fastcgi.h 1970-01-01 03:00:00.000000000 +0300
33240 +++ lighttpd-1.5.0/src/mod_proxy_backend_fastcgi.h 2006-09-07 00:57:05.000000000 +0300
33242 +#ifndef _MOD_PROXY_BACKEND_FASTCGI_H_
33243 +#define _MOD_PROXY_BACKEND_FASTCGI_H_
33245 +#include "mod_proxy_core.h"
33248 +int proxy_fastcgi_stream_decoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out);
33249 +int proxy_fastcgi_stream_encoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out);
33251 +parse_status_t proxy_fastcgi_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq);
33252 +int proxy_fastcgi_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq);
33255 --- ../lighttpd-1.4.11/src/mod_proxy_backend_http.c 1970-01-01 03:00:00.000000000 +0300
33256 +++ lighttpd-1.5.0/src/mod_proxy_backend_http.c 2006-09-07 00:57:05.000000000 +0300
33258 +#include <stdlib.h>
33259 +#include <string.h>
33261 +#include "mod_proxy_core.h"
33262 +#include "configfile.h"
33263 +#include "buffer.h"
33265 +#include "sys-strings.h"
33267 +void chunkqueue_skip(chunkqueue *cq, off_t skip) {
33270 + for (c = cq->first; c && skip; c = c->next) {
33271 + if (skip > c->mem->used - c->offset - 1) {
33272 + skip -= c->mem->used - c->offset - 1;
33274 + c->offset += skip;
33282 +int proxy_http_stream_decoder(server *srv, proxy_session *sess, chunkqueue *raw, chunkqueue *decoded) {
33285 + if (raw->first == NULL) return 0;
33287 + if (sess->is_chunked) {
33289 + /* the start should always be a chunk-length */
33290 + off_t chunk_len = 0;
33291 + char *err = NULL;
33292 + int chunklen_strlen = 0;
33294 + off_t we_have = 0, we_need = 0;
33298 + if (c->mem->used == 0) return 0;
33300 + chunk_len = strtol(BUF_STR(c->mem) + c->offset, &err, 16);
33301 + if (!(*err == ' ' || *err == '\r' || *err == ';')) {
33302 + if (*err == '\0') {
33303 + /* we just need more data */
33309 + if (chunk_len < 0) {
33310 + ERROR("chunk_len is negative: %Ld", chunk_len);
33314 + chunklen_strlen = err - (BUF_STR(c->mem) + c->offset);
33315 + chunklen_strlen++; /* skip the err-char */
33318 + ch = BUF_STR(c->mem)[c->offset + chunklen_strlen];
33323 + /* bingo, chunk-header is finished */
33328 + chunklen_strlen++;
33329 + } while (ch != '\n' && c != '\0');
33331 + if (ch != '\n') {
33332 + ERROR("%s", "missing the CRLF");
33336 + we_need = chunk_len + chunklen_strlen + 2;
33337 + /* do we have the full chunk ? */
33338 + for (c = raw->first; c; c = c->next) {
33339 + we_have += c->mem->used - 1 - c->offset;
33341 + /* we have enough, jump out */
33342 + if (we_have > we_need) break;
33345 + /* get more data */
33346 + if (we_have < we_need) {
33350 + /* skip the chunk-header */
33351 + chunkqueue_skip(raw, chunklen_strlen);
33353 + /* final chunk */
33354 + if (chunk_len == 0) {
33355 + chunkqueue_skip(raw, 2);
33360 + /* we have enough, copy the data */
33361 + for (c = raw->first; c && chunk_len; c = c->next) {
33362 + off_t we_want = 0;
33363 + buffer *b = chunkqueue_get_append_buffer(decoded);
33365 + we_want = chunk_len > (c->mem->used - c->offset - 1) ? c->mem->used - c->offset - 1: chunk_len;
33367 + buffer_copy_string_len(b, c->mem->ptr + c->offset, we_want);
33369 + c->offset += we_want;
33370 + chunk_len -= we_want;
33373 + /* skip the \r\n */
33374 + chunkqueue_skip(raw, 2);
33376 + /* we are done, give the connection to someone else */
33377 + chunkqueue_remove_finished_chunks(raw);
33380 + /* no chunked encoding, ok, perhaps a content-length ? */
33382 + chunkqueue_remove_finished_chunks(raw);
33383 + for (c = raw->first; c; c = c->next) {
33386 + if (c->mem->used == 0) continue;
33388 + b = chunkqueue_get_append_buffer(decoded);
33390 + sess->bytes_read += c->mem->used - c->offset - 1;
33392 + buffer_copy_string_len(b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
33394 + c->offset = c->mem->used - 1;
33396 + if (sess->bytes_read == sess->content_length) {
33401 + if (sess->bytes_read == sess->content_length) {
33402 + return 1; /* finished */
33410 + * transform the content-stream into a valid HTTP-content-stream
33412 + * as we don't apply chunked-encoding here, pass it on AS IS
33414 +int proxy_http_stream_encoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out) {
33417 + /* there is nothing that we have to send out anymore */
33418 + if (in->bytes_in == in->bytes_out &&
33419 + in->is_closed) return 0;
33421 + for (c = in->first; in->bytes_out < in->bytes_in; c = c->next) {
33423 + off_t weWant = in->bytes_in - in->bytes_out;
33424 + off_t weHave = 0;
33426 + /* we announce toWrite octects
33427 + * now take all the request_content chunk that we need to fill this request
33430 + switch (c->type) {
33432 + weHave = c->file.length - c->offset;
33434 + if (weHave > weWant) weHave = weWant;
33436 + chunkqueue_append_file(out, c->file.name, c->offset, weHave);
33438 + c->offset += weHave;
33439 + in->bytes_out += weHave;
33441 + out->bytes_in += weHave;
33445 + /* append to the buffer */
33446 + weHave = c->mem->used - 1 - c->offset;
33448 + if (weHave > weWant) weHave = weWant;
33450 + b = chunkqueue_get_append_buffer(out);
33451 + buffer_append_memory(b, c->mem->ptr + c->offset, weHave);
33452 + b->used++; /* add virtual \0 */
33454 + c->offset += weHave;
33455 + in->bytes_out += weHave;
33457 + out->bytes_in += weHave;
33469 + * generate a HTTP/1.1 proxy request from the set of request-headers
33471 + * TODO: this is HTTP-proxy specific and will be moved moved into a separate backed
33474 +int proxy_http_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
33478 + b = chunkqueue_get_append_buffer(cq);
33480 + /* request line */
33481 + buffer_copy_string(b, get_http_method_name(con->request.http_method));
33482 + BUFFER_APPEND_STRING_CONST(b, " ");
33484 + /* check if we want to rewrite the uri */
33486 + for (i = 0; i < p->conf.request_rewrites->used; i++) {
33487 + proxy_rewrite *rw = p->conf.request_rewrites->ptr[i];
33489 + if (buffer_is_equal_string(rw->header, CONST_STR_LEN("_uri"))) {
33492 + if ((ret = pcre_replace(rw->regex, rw->replace, con->request.uri, p->replace_buf)) < 0) {
33494 + case PCRE_ERROR_NOMATCH:
33495 + /* hmm, ok. no problem */
33496 + buffer_append_string_buffer(b, con->request.uri);
33499 + TRACE("oops, pcre_replace failed with: %d", ret);
33503 + buffer_append_string_buffer(b, p->replace_buf);
33510 + if (i == p->conf.request_rewrites->used) {
33512 + buffer_append_string_buffer(b, con->request.uri);
33515 + if (con->request.http_version == HTTP_VERSION_1_1) {
33516 + BUFFER_APPEND_STRING_CONST(b, " HTTP/1.1\r\n");
33518 + BUFFER_APPEND_STRING_CONST(b, " HTTP/1.0\r\n");
33521 + for (i = 0; i < sess->request_headers->used; i++) {
33524 + ds = (data_string *)sess->request_headers->data[i];
33526 + buffer_append_string_buffer(b, ds->key);
33527 + BUFFER_APPEND_STRING_CONST(b, ": ");
33528 + buffer_append_string_buffer(b, ds->value);
33529 + BUFFER_APPEND_STRING_CONST(b, "\r\n");
33532 + BUFFER_APPEND_STRING_CONST(b, "\r\n");
33538 + * parse the response header
33540 + * NOTE: this can be used by all backends as they all send a HTTP-Response a clean block
33541 + * - fastcgi needs some decoding for the protocol
33543 +parse_status_t proxy_http_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
33544 + int have_content_length = 0;
33547 + http_response_reset(p->resp);
33549 + switch (http_response_parse_cq(cq, p->resp)) {
33550 + case PARSE_ERROR:
33551 + /* parsing failed */
33553 + return PARSE_ERROR;
33554 + case PARSE_NEED_MORE:
33555 + return PARSE_NEED_MORE;
33556 + case PARSE_SUCCESS:
33557 + con->http_status = p->resp->status;
33559 + chunkqueue_remove_finished_chunks(cq);
33561 + sess->content_length = -1;
33563 + /* copy the http-headers */
33564 + for (i = 0; i < p->resp->headers->used; i++) {
33565 + const char *ign[] = { "Status", NULL };
33569 + data_string *header = (data_string *)p->resp->headers->data[i];
33571 + /* some headers are ignored by default */
33572 + for (j = 0; ign[j]; j++) {
33573 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
33575 + if (ign[j]) continue;
33577 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
33578 + /* CGI/1.1 rev 03 - 7.2.1.2 */
33579 + if (con->http_status == 0) con->http_status = 302;
33580 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
33581 + have_content_length = 1;
33583 + sess->content_length = strtol(header->value->ptr, NULL, 10);
33585 + if (sess->content_length < 0) {
33586 + return PARSE_ERROR;
33588 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Sendfile")) ||
33589 + 0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-LIGHTTPD-Sendfile"))) {
33590 + if (p->conf.allow_x_sendfile) {
33591 + sess->send_response_content = 0;
33592 + sess->do_internal_redirect = 1;
33594 + /* don't try to rewrite this request through mod_proxy_core again */
33595 + sess->internal_redirect_count = MAX_INTERNAL_REDIRECTS;
33597 + buffer_copy_string_buffer(con->physical.path, header->value);
33599 + /* as we want to support ETag and friends we set the physical path for the file
33600 + * and hope mod_staticfile catches up */
33604 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Rewrite-URI"))) {
33605 + if (p->conf.allow_x_rewrite) {
33606 + sess->send_response_content = 0;
33607 + sess->do_internal_redirect = 1;
33609 + buffer_copy_string_buffer(con->request.uri, header->value);
33610 + buffer_reset(con->physical.path);
33612 + config_cond_cache_reset(srv, con);
33616 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Rewrite-Host"))) {
33617 + if (p->conf.allow_x_rewrite) {
33618 + sess->send_response_content = 0;
33619 + sess->do_internal_redirect = 1;
33621 + buffer_copy_string_buffer(con->request.http_host, header->value);
33622 + buffer_reset(con->physical.path);
33624 + config_cond_cache_reset(srv, con);
33628 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Transfer-Encoding"))) {
33629 + if (strstr(header->value->ptr, "chunked")) {
33630 + sess->is_chunked = 1;
33632 + /* ignore the header */
33634 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Connection"))) {
33635 + if (strstr(header->value->ptr, "close")) {
33636 + sess->is_closing = 1;
33638 + /* ignore the header */
33643 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
33644 + ds = data_response_init();
33648 + buffer_copy_string_buffer(ds->key, header->key);
33650 + for (k = 0; k < p->conf.response_rewrites->used; k++) {
33651 + proxy_rewrite *rw = p->conf.response_rewrites->ptr[k];
33653 + if (buffer_is_equal(rw->header, header->key)) {
33656 + if ((ret = pcre_replace(rw->regex, rw->replace, header->value, p->replace_buf)) < 0) {
33658 + case PCRE_ERROR_NOMATCH:
33659 + /* hmm, ok. no problem */
33660 + buffer_append_string_buffer(ds->value, header->value);
33663 + TRACE("oops, pcre_replace failed with: %d", ret);
33667 + buffer_append_string_buffer(ds->value, p->replace_buf);
33674 + if (k == p->conf.response_rewrites->used) {
33675 + buffer_copy_string_buffer(ds->value, header->value);
33678 + array_insert_unique(con->response.headers, (data_unset *)ds);
33681 + /* does the client allow us to send chunked encoding ? */
33682 + if (con->request.http_version == HTTP_VERSION_1_1 &&
33683 + !have_content_length) {
33684 + con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
33690 + return PARSE_SUCCESS; /* we have a full header */
33694 --- ../lighttpd-1.4.11/src/mod_proxy_backend_http.h 1970-01-01 03:00:00.000000000 +0300
33695 +++ lighttpd-1.5.0/src/mod_proxy_backend_http.h 2006-09-07 00:57:05.000000000 +0300
33697 +#ifndef _MOD_PROXY_BACKEND_HTTP_H_
33698 +#define _MOD_PROXY_BACKEND_HTTP_H_
33700 +#include "mod_proxy_core.h"
33703 +int proxy_http_stream_decoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out);
33704 +int proxy_http_stream_encoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out);
33706 +parse_status_t proxy_http_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq);
33707 +int proxy_http_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq);
33710 --- ../lighttpd-1.4.11/src/mod_proxy_core.c 1970-01-01 03:00:00.000000000 +0300
33711 +++ lighttpd-1.5.0/src/mod_proxy_core.c 2006-09-07 00:57:05.000000000 +0300
33713 +#include <string.h>
33714 +#include <stdlib.h>
33715 +#include <fcntl.h>
33716 +#include <errno.h>
33717 +#include <ctype.h>
33718 +#include <assert.h>
33720 +#include "buffer.h"
33721 +#include "array.h"
33725 +#include "plugin.h"
33726 +#include "joblist.h"
33727 +#include "sys-files.h"
33728 +#include "inet_ntop_cache.h"
33729 +#include "crc32.h"
33730 +#include "configfile.h"
33732 +#include "mod_proxy_core.h"
33733 +#include "mod_proxy_backend_http.h"
33734 +#include "mod_proxy_backend_fastcgi.h"
33736 +#define CONFIG_PROXY_CORE_BALANCER "proxy-core.balancer"
33737 +#define CONFIG_PROXY_CORE_PROTOCOL "proxy-core.protocol"
33738 +#define CONFIG_PROXY_CORE_DEBUG "proxy-core.debug"
33739 +#define CONFIG_PROXY_CORE_BACKENDS "proxy-core.backends"
33740 +#define CONFIG_PROXY_CORE_REWRITE_REQUEST "proxy-core.rewrite-request"
33741 +#define CONFIG_PROXY_CORE_REWRITE_RESPONSE "proxy-core.rewrite-response"
33742 +#define CONFIG_PROXY_CORE_ALLOW_X_SENDFILE "proxy-core.allow-x-sendfile"
33743 +#define CONFIG_PROXY_CORE_ALLOW_X_REWRITE "proxy-core.allow-x-rewrite"
33744 +#define CONFIG_PROXY_CORE_MAX_POOL_SIZE "proxy-core.max-pool-size"
33746 +int array_insert_int(array *a, const char *key, int val) {
33747 + data_integer *di;
33749 + if (NULL == (di = (data_integer *)array_get_unused_element(a, TYPE_INTEGER))) {
33750 + di = data_integer_init();
33753 + buffer_copy_string(di->key, key);
33755 + array_insert_unique(a, (data_unset *)di);
33760 +INIT_FUNC(mod_proxy_core_init) {
33763 + p = calloc(1, sizeof(*p));
33765 + /* create some backends as long as we don't have the config-parser */
33767 + p->possible_balancers = array_init();
33768 + array_insert_int(p->possible_balancers, "fair", PROXY_BALANCE_FAIR);
33769 + array_insert_int(p->possible_balancers, "hash", PROXY_BALANCE_HASH);
33770 + array_insert_int(p->possible_balancers, "round-robin", PROXY_BALANCE_RR);
33772 + p->possible_protocols = array_init();
33773 + array_insert_int(p->possible_protocols, "http", PROXY_PROTOCOL_HTTP);
33774 + array_insert_int(p->possible_protocols, "fastcgi", PROXY_PROTOCOL_FASTCGI);
33775 + array_insert_int(p->possible_protocols, "scgi", PROXY_PROTOCOL_SCGI);
33776 + array_insert_int(p->possible_protocols, "https", PROXY_PROTOCOL_HTTPS);
33778 + p->balance_buf = buffer_init();
33779 + p->protocol_buf = buffer_init();
33780 + p->replace_buf = buffer_init();
33781 + p->backends_arr = array_init();
33783 + p->tmp_buf = buffer_init();
33785 + p->resp = http_response_init();
33790 +FREE_FUNC(mod_proxy_core_free) {
33791 + plugin_data *p = p_d;
33793 + if (!p) return HANDLER_GO_ON;
33795 + if (p->config_storage) {
33797 + for (i = 0; i < srv->config_context->used; i++) {
33798 + plugin_config *s = p->config_storage[i];
33800 + if (!s) continue;
33802 + proxy_backends_free(s->backends);
33803 + proxy_backlog_free(s->backlog);
33805 + proxy_rewrites_free(s->request_rewrites);
33806 + proxy_rewrites_free(s->response_rewrites);
33810 + free(p->config_storage);
33813 + array_free(p->possible_protocols);
33814 + array_free(p->possible_balancers);
33815 + array_free(p->backends_arr);
33817 + buffer_free(p->balance_buf);
33818 + buffer_free(p->protocol_buf);
33819 + buffer_free(p->replace_buf);
33820 + buffer_free(p->tmp_buf);
33822 + http_response_free(p->resp);
33826 + return HANDLER_GO_ON;
33829 +static handler_t mod_proxy_core_config_parse_rewrites(proxy_rewrites *dest, array *src, const char *config_key) {
33833 + if (NULL != (du = array_get_element(src, config_key))) {
33834 + data_array *keys = (data_array *)du;
33836 + if (keys->type != TYPE_ARRAY) {
33837 + ERROR("%s = <...>",
33840 + return HANDLER_ERROR;
33844 + * proxy-core.rewrite-request = (
33845 + * "_uri" => ( ... )
33849 + for (j = 0; j < keys->value->used; j++) {
33851 + data_array *headers = (data_array *)keys->value->data[j];
33853 + /* keys->key should be "_uri" and the value a array of rewrite */
33854 + if (headers->type != TYPE_ARRAY) {
33855 + ERROR("%s = ( %s => <...> ) has to a array",
33857 + BUF_STR(headers->key));
33859 + return HANDLER_ERROR;
33862 + if (headers->value->used > 1) {
33863 + ERROR("%s = ( %s => <...> ) has to a array with only one element",
33865 + BUF_STR(headers->key));
33867 + return HANDLER_ERROR;
33871 + for (k = 0; k < headers->value->used; k++) {
33872 + data_string *rewrites = (data_string *)headers->value->data[k];
33873 + proxy_rewrite *rw;
33875 + /* keys->key should be "_uri" and the value a array of rewrite */
33876 + if (rewrites->type != TYPE_STRING) {
33877 + ERROR("%s = ( \"%s\" => ( \"%s\" => <value> ) ) has to a string",
33879 + BUF_STR(headers->key),
33880 + BUF_STR(rewrites->key));
33882 + return HANDLER_ERROR;
33885 + rw = proxy_rewrite_init();
33887 + if (0 != proxy_rewrite_set_regex(rw, rewrites->key)) {
33888 + return HANDLER_ERROR;
33890 + buffer_copy_string_buffer(rw->replace, rewrites->value);
33891 + buffer_copy_string_buffer(rw->match, rewrites->key);
33892 + buffer_copy_string_buffer(rw->header, headers->key);
33894 + proxy_rewrites_add(dest, rw);
33899 + return HANDLER_GO_ON;
33903 +SETDEFAULTS_FUNC(mod_proxy_core_set_defaults) {
33904 + plugin_data *p = p_d;
33907 + config_values_t cv[] = {
33908 + { CONFIG_PROXY_CORE_BACKENDS, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
33909 + { CONFIG_PROXY_CORE_DEBUG, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
33910 + { CONFIG_PROXY_CORE_BALANCER, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
33911 + { CONFIG_PROXY_CORE_PROTOCOL, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
33912 + { CONFIG_PROXY_CORE_REWRITE_REQUEST, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
33913 + { CONFIG_PROXY_CORE_REWRITE_RESPONSE, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
33914 + { CONFIG_PROXY_CORE_ALLOW_X_SENDFILE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
33915 + { CONFIG_PROXY_CORE_ALLOW_X_REWRITE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
33916 + { CONFIG_PROXY_CORE_MAX_POOL_SIZE, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
33917 + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
33920 + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
33922 + for (i = 0; i < srv->config_context->used; i++) {
33923 + plugin_config *s;
33925 + proxy_backend *backend;
33927 + array_reset(p->backends_arr);
33928 + buffer_reset(p->balance_buf);
33929 + buffer_reset(p->protocol_buf);
33931 + s = calloc(1, sizeof(plugin_config));
33933 + s->balancer = PROXY_BALANCE_UNSET;
33934 + s->protocol = PROXY_PROTOCOL_UNSET;
33935 + s->backends = proxy_backends_init();
33936 + s->backlog = proxy_backlog_init();
33937 + s->response_rewrites = proxy_rewrites_init();
33938 + s->request_rewrites = proxy_rewrites_init();
33940 + cv[0].destination = p->backends_arr;
33941 + cv[1].destination = &(s->debug);
33942 + cv[2].destination = p->balance_buf; /* parse into a constant */
33943 + cv[3].destination = p->protocol_buf; /* parse into a constant */
33944 + cv[6].destination = &(s->allow_x_sendfile);
33945 + cv[7].destination = &(s->allow_x_rewrite);
33946 + cv[8].destination = &(s->max_pool_size);
33948 + buffer_reset(p->balance_buf);
33950 + p->config_storage[i] = s;
33951 + ca = ((data_config *)srv->config_context->data[i])->value;
33953 + if (0 != config_insert_values_global(srv, ca, cv)) {
33954 + return HANDLER_ERROR;
33957 + if (!buffer_is_empty(p->balance_buf)) {
33958 + data_integer *di;
33960 + if (NULL == (di = (data_integer *)array_get_element(p->possible_balancers, BUF_STR(p->balance_buf)))) {
33961 + ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->balance_buf));
33963 + return HANDLER_ERROR;
33966 + s->balancer = di->value;
33969 + if (!buffer_is_empty(p->protocol_buf)) {
33970 + data_integer *di;
33972 + if (NULL == (di = (data_integer *)array_get_element(p->possible_protocols, BUF_STR(p->protocol_buf)))) {
33973 + ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->protocol_buf));
33975 + return HANDLER_ERROR;
33978 + s->protocol = di->value;
33981 + if (p->backends_arr->used) {
33982 + backend = proxy_backend_init();
33984 + /* check if the backends have a valid host-name */
33985 + for (j = 0; j < p->backends_arr->used; j++) {
33986 + data_string *ds = (data_string *)p->backends_arr->data[j];
33988 + /* the values should be ips or hostnames */
33989 + if (0 != proxy_address_pool_add_string(backend->address_pool, ds->value)) {
33990 + return HANDLER_ERROR;
33994 + if (s->max_pool_size) {
33995 + backend->pool->max_size = s->max_pool_size;
33998 + proxy_backends_add(s->backends, backend);
34001 + if (HANDLER_GO_ON != mod_proxy_core_config_parse_rewrites(s->request_rewrites, ca, CONFIG_PROXY_CORE_REWRITE_REQUEST)) {
34002 + return HANDLER_ERROR;
34005 + if (HANDLER_GO_ON != mod_proxy_core_config_parse_rewrites(s->response_rewrites, ca, CONFIG_PROXY_CORE_REWRITE_RESPONSE)) {
34006 + return HANDLER_ERROR;
34010 + return HANDLER_GO_ON;
34014 +proxy_session *proxy_session_init(void) {
34015 + proxy_session *sess;
34017 + sess = calloc(1, sizeof(*sess));
34019 + sess->state = PROXY_STATE_UNSET;
34020 + sess->request_headers = array_init();
34021 + sess->env_headers = array_init();
34023 + sess->recv = chunkqueue_init();
34024 + sess->recv_raw = chunkqueue_init();
34025 + sess->send_raw = chunkqueue_init();
34026 + sess->send = chunkqueue_init();
34028 + sess->is_chunked = 0;
34029 + sess->send_response_content = 1;
34034 +void proxy_session_free(proxy_session *sess) {
34035 + if (!sess) return;
34037 + array_free(sess->request_headers);
34038 + array_free(sess->env_headers);
34040 + chunkqueue_free(sess->recv);
34041 + chunkqueue_free(sess->recv_raw);
34042 + chunkqueue_free(sess->send_raw);
34043 + chunkqueue_free(sess->send);
34049 + * decode the content for the protocol
34051 + * http might have chunk-encoding
34052 + * fastcgi has the fastcgi wrapper code
34054 + * @param in chunkqueue for the encoded, protocol specific data
34055 + * @param out chunkqueue for the plain content
34058 +int proxy_stream_decoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out) {
34059 + switch (sess->proxy_backend->protocol) {
34060 + case PROXY_PROTOCOL_HTTP:
34061 + return proxy_http_stream_decoder(srv, sess, in, out);
34062 + case PROXY_PROTOCOL_FASTCGI:
34063 + return proxy_fastcgi_stream_decoder(srv, sess, in, out);
34065 + ERROR("protocol %d is not supported yet", sess->proxy_backend->protocol);
34070 + * encode the content for the protocol
34072 + * @param in chunkqueue with the content to (no encoding)
34073 + * @param out chunkqueue for the encoded, protocol specific data
34075 +int proxy_stream_encoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out) {
34076 + switch (sess->proxy_backend->protocol) {
34077 + case PROXY_PROTOCOL_HTTP:
34078 + return proxy_http_stream_encoder(srv, sess, in, out);
34079 + case PROXY_PROTOCOL_FASTCGI:
34080 + return proxy_fastcgi_stream_encoder(srv, sess, in, out);
34082 + ERROR("protocol %d is not supported yet", sess->proxy_backend->protocol);
34087 +int proxy_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
34088 + switch (sess->proxy_backend->protocol) {
34089 + case PROXY_PROTOCOL_HTTP:
34090 + return proxy_http_get_request_chunk(srv, con, p, sess, cq);
34091 + case PROXY_PROTOCOL_FASTCGI:
34092 + return proxy_fastcgi_get_request_chunk(srv, con, p, sess, cq);
34094 + ERROR("protocol %d is not supported yet", sess->proxy_backend->protocol);
34100 +parse_status_t proxy_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
34101 + switch (sess->proxy_backend->protocol) {
34102 + case PROXY_PROTOCOL_HTTP:
34103 + return proxy_http_parse_response_header(srv, con, p, sess, cq);
34104 + case PROXY_PROTOCOL_FASTCGI:
34105 + return proxy_fastcgi_parse_response_header(srv, con, p, sess, cq);
34107 + ERROR("protocol %d is not supported yet", sess->proxy_backend->protocol);
34108 + return PARSE_ERROR;
34113 +handler_t proxy_connection_connect(proxy_connection *con) {
34116 + if (-1 == (fd = socket(con->address->addr.plain.sa_family, SOCK_STREAM, 0))) {
34119 + fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
34121 + con->sock->fd = fd;
34122 + con->sock->fde_ndx = -1;
34123 + con->sock->type = IOSOCKET_TYPE_SOCKET;
34125 + if (-1 == connect(fd, &(con->address->addr.plain), sizeof(con->address->addr))) {
34127 + case EINPROGRESS:
34130 + return HANDLER_WAIT_FOR_EVENT;
34133 + con->sock->fd = -1;
34135 + return HANDLER_ERROR;
34139 + return HANDLER_GO_ON;
34143 + * event-handler for idling connections
34145 + * unused (idling) keep-alive connections are not bound to a session
34146 + * and need their own event-handler
34148 + * if the connection closes (we get a FDEVENT_IN), close our side too and
34149 + * let the trigger-func handle the cleanup
34151 + * @see proxy_trigger
34155 +static handler_t proxy_handle_fdevent_idle(void *s, void *ctx, int revents) {
34156 + server *srv = (server *)s;
34157 + proxy_connection *proxy_con = ctx;
34159 + if (revents & FDEVENT_IN) {
34160 + switch (proxy_con->state) {
34161 + case PROXY_CONNECTION_STATE_IDLE:
34162 + proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
34164 + /* close + unregister have to be in the same call,
34165 + * otherwise we get a events for a re-opened fd */
34167 + fdevent_event_del(srv->ev, proxy_con->sock);
34170 + case PROXY_CONNECTION_STATE_CLOSED:
34171 + /* poll() is state-driven, we will get events as long as it isn't disabled
34172 + * the close() above should disable the events too */
34173 + ERROR("%s", "hurry up buddy, I got another event for a closed idle-connection");
34176 + ERROR("invalid connection state: %d, should be idle", proxy_con->state);
34181 + return HANDLER_GO_ON;
34185 +/* don't call any proxy functions directly */
34186 +static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) {
34187 + server *srv = (server *)s;
34188 + proxy_session *sess = ctx;
34189 + connection *con = sess->remote_con;
34191 + if (revents & FDEVENT_OUT) {
34192 + switch (sess->state) {
34193 + case PROXY_STATE_CONNECTING: /* delayed connect */
34194 + case PROXY_STATE_WRITE_REQUEST_HEADER:
34195 + case PROXY_STATE_WRITE_REQUEST_BODY:
34196 + /* we are still connection */
34198 + joblist_append(srv, con);
34201 + ERROR("oops, unexpected state for fdevent-out %d", sess->state);
34204 + } else if (revents & FDEVENT_IN) {
34207 + switch (sess->state) {
34208 + case PROXY_STATE_READ_RESPONSE_HEADER:
34209 + /* call our header parser */
34210 + joblist_append(srv, con);
34212 + case PROXY_STATE_READ_RESPONSE_BODY:
34213 + /* we should be in the WRITE state now,
34214 + * just read in the content and forward it to the outgoing connection
34217 + chunkqueue_remove_finished_chunks(sess->recv_raw);
34218 + switch (srv->network_backend_read(srv, con, sess->proxy_con->sock, sess->recv_raw)) {
34219 + case NETWORK_STATUS_CONNECTION_CLOSE:
34220 + fdevent_event_del(srv->ev,sess->proxy_con->sock);
34222 + /* the connection is gone
34223 + * make the connect */
34224 + con->send->is_closed = 1;
34225 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
34227 + case NETWORK_STATUS_SUCCESS:
34228 + /* read even more, do we have all the content */
34230 + /* how much do we want to read ? */
34232 + /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
34234 + switch (proxy_stream_decoder(srv, sess, sess->recv_raw, sess->recv)) {
34242 + /* we are done */
34243 + con->send->is_closed = 1;
34247 + chunkqueue_remove_finished_chunks(sess->recv_raw);
34250 + /* copy the content to the next cq */
34251 + for (c = sess->recv->first; c; c = c->next) {
34252 + if (c->mem->used == 0) continue;
34254 + if (sess->send_response_content) {
34255 + /* X-Sendfile ignores the content-body */
34256 + chunkqueue_append_mem(con->send, c->mem->ptr + c->offset, c->mem->used - c->offset);
34259 + c->offset = c->mem->used - 1;
34262 + chunkqueue_remove_finished_chunks(sess->recv);
34266 + ERROR("%s", "oops, we failed to read");
34270 + /* we wrote something into the the send-buffers,
34271 + * call the connection-handler to push it to the client */
34272 + joblist_append(srv, con);
34275 + ERROR("oops, unexpected state for fdevent-in %d", sess->state);
34280 + if (revents & FDEVENT_HUP) {
34281 + /* someone closed our connection */
34282 + switch (sess->state) {
34283 + case PROXY_STATE_CONNECTING:
34284 + /* let the getsockopt() catch this */
34285 + joblist_append(srv, con);
34287 + case PROXY_STATE_READ_RESPONSE_BODY:
34288 + /* the keep-alive race-condition */
34291 + ERROR("oops, unexpected state for fdevent-hup %d", sess->state);
34296 + return HANDLER_GO_ON;
34298 +void proxy_set_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
34299 + data_string *ds_dst;
34301 + if (NULL != (ds_dst = (data_string *)array_get_element(hdrs, key))) {
34302 + buffer_copy_string_len(ds_dst->value, value, val_len);
34306 + if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
34307 + ds_dst = data_string_init();
34310 + buffer_copy_string_len(ds_dst->key, key, key_len);
34311 + buffer_copy_string_len(ds_dst->value, value, val_len);
34312 + array_insert_unique(hdrs, (data_unset *)ds_dst);
34315 +void proxy_append_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
34316 + data_string *ds_dst;
34318 + if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
34319 + ds_dst = data_string_init();
34322 + buffer_copy_string_len(ds_dst->key, key, key_len);
34323 + buffer_copy_string_len(ds_dst->value, value, val_len);
34324 + array_insert_unique(hdrs, (data_unset *)ds_dst);
34329 + * build the request-header array and call the backend specific request formater
34330 + * to fill the chunkqueue
34332 +int proxy_get_request_header(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
34333 + /* request line */
34334 + const char *remote_ip;
34337 + remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
34338 + proxy_append_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-For"), remote_ip, strlen(remote_ip));
34340 + /* http_host is NOT is just a pointer to a buffer
34341 + * which is NULL if it is not set */
34342 + if (con->request.http_host &&
34343 + !buffer_is_empty(con->request.http_host)) {
34344 + proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Host"), CONST_BUF_LEN(con->request.http_host));
34346 + if (con->conf.is_ssl) {
34347 + proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("https"));
34349 + proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("http"));
34352 + /* request header */
34353 + for (i = 0; i < con->request.headers->used; i++) {
34357 + ds = (data_string *)con->request.headers->data[i];
34359 + if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
34361 + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
34362 + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
34364 + for (k = 0; k < p->conf.request_rewrites->used; k++) {
34365 + proxy_rewrite *rw = p->conf.request_rewrites->ptr[k];
34367 + if (buffer_is_equal(rw->header, ds->key)) {
34370 + if ((ret = pcre_replace(rw->regex, rw->replace, ds->value, p->replace_buf)) < 0) {
34372 + case PCRE_ERROR_NOMATCH:
34373 + /* hmm, ok. no problem */
34374 + proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
34377 + TRACE("oops, pcre_replace failed with: %d", ret);
34381 + proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(p->replace_buf));
34388 + if (k == p->conf.request_rewrites->used) {
34389 + proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
34393 + proxy_get_request_chunk(srv, con, p, sess, sess->send_raw);
34399 +/* we are event-driven
34401 + * the first entry is connect() call, if the doesn't need a event
34404 + * - connect (+ delayed connect)
34405 + * - write header + content
34406 + * - read header + content
34408 + * as soon as have read the response header we switch con->file_started and return HANDLER_GO_ON to
34409 + * tell the core we are ready to stream out the content.
34411 +handler_t proxy_state_engine(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
34412 + /* do we have a connection ? */
34414 + if (sess->state == PROXY_STATE_UNSET) {
34415 + /* we are not started yet */
34416 + sess->connect_start_ts = srv->cur_ts;
34417 + switch(proxy_connection_connect(sess->proxy_con)) {
34418 + case HANDLER_WAIT_FOR_EVENT:
34419 + /* waiting on the connect call */
34421 + fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
34422 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
34424 + sess->state = PROXY_STATE_CONNECTING;
34425 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
34427 + return HANDLER_WAIT_FOR_EVENT;
34428 + case HANDLER_GO_ON:
34429 + /* we are connected */
34430 + sess->state = PROXY_STATE_CONNECTED;
34431 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
34432 + fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
34435 + case HANDLER_ERROR:
34437 + /* not good, something failed */
34438 + return HANDLER_ERROR;
34441 + } else if (sess->state == PROXY_STATE_CONNECTING) {
34442 + int socket_error;
34443 + socklen_t socket_error_len = sizeof(socket_error);
34445 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
34447 + if (0 != getsockopt(sess->proxy_con->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
34448 + ERROR("getsockopt failed:", strerror(errno));
34450 + return HANDLER_ERROR;
34452 + if (socket_error != 0) {
34453 + switch (socket_error) {
34454 + case ECONNREFUSED:
34455 + /* there is no-one on the other side */
34456 + sess->proxy_con->address->disabled_until = srv->cur_ts + 2;
34458 + TRACE("address %s refused us, disabling for 2 sec", sess->proxy_con->address->name->ptr);
34460 + case EHOSTUNREACH:
34461 + /* there is no-one on the other side */
34462 + sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
34464 + TRACE("host %s is unreachable, disabling for 60 sec", sess->proxy_con->address->name->ptr);
34467 + sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
34469 + TRACE("connected finally failed: %s (%d)", strerror(socket_error), socket_error);
34471 + TRACE("connect to address %s failed and I don't know why, disabling for 10 sec", sess->proxy_con->address->name->ptr);
34476 + sess->proxy_con->address->state = PROXY_ADDRESS_STATE_DISABLED;
34478 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
34479 + return HANDLER_COMEBACK;
34482 + sess->state = PROXY_STATE_CONNECTED;
34483 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
34486 + if (sess->state == PROXY_STATE_CONNECTED) {
34487 + /* build the header */
34488 + proxy_get_request_header(srv, con, p, sess);
34490 + sess->state = PROXY_STATE_WRITE_REQUEST_HEADER;
34493 + switch (sess->state) {
34494 + case PROXY_STATE_WRITE_REQUEST_HEADER:
34495 + /* create the request-packet */
34496 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
34498 + switch (srv->network_backend_write(srv, con, sess->proxy_con->sock, sess->send_raw)) {
34499 + case NETWORK_STATUS_SUCCESS:
34500 + sess->state = PROXY_STATE_WRITE_REQUEST_BODY;
34502 + case NETWORK_STATUS_WAIT_FOR_EVENT:
34503 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
34505 + return HANDLER_WAIT_FOR_EVENT;
34506 + case NETWORK_STATUS_CONNECTION_CLOSE:
34507 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
34509 + /* this connection is closed, restart the request with a new connection */
34511 + return HANDLER_COMEBACK;
34513 + return HANDLER_ERROR;
34516 + chunkqueue_remove_finished_chunks(sess->send_raw);
34518 + /* fall through */
34519 + case PROXY_STATE_WRITE_REQUEST_BODY:
34520 + /* do we have a content-body to send up to the backend ? */
34522 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
34524 + proxy_stream_encoder(srv, sess, con->recv, sess->send_raw);
34526 + chunkqueue_remove_finished_chunks(con->recv);
34528 + switch (srv->network_backend_write(srv, con, sess->proxy_con->sock, sess->send_raw)) {
34529 + case NETWORK_STATUS_SUCCESS:
34530 + if (con->recv->is_closed && /* no further input */
34531 + con->recv->bytes_in == con->recv->bytes_out && /* everything is encoded */
34532 + sess->send_raw->bytes_in == sess->send_raw->bytes_out) { /* everything is sent */
34533 + sess->state = PROXY_STATE_READ_RESPONSE_HEADER;
34536 + case NETWORK_STATUS_WAIT_FOR_EVENT:
34537 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
34539 + chunkqueue_remove_finished_chunks(sess->send_raw);
34541 + return HANDLER_WAIT_FOR_EVENT;
34542 + case NETWORK_STATUS_CONNECTION_CLOSE:
34543 + /* the connection got close while sending the request content up
34544 + * to the backend, for now handle this as error */
34546 + TRACE("%s", "(con-close)");
34547 + return HANDLER_ERROR;
34549 + TRACE("%s", "(error)");
34550 + return HANDLER_ERROR;
34552 + chunkqueue_remove_finished_chunks(sess->send_raw);
34554 + /* fall through */
34555 + case PROXY_STATE_READ_RESPONSE_HEADER:
34556 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
34558 + chunkqueue_remove_finished_chunks(sess->recv_raw);
34560 + switch (srv->network_backend_read(srv, con, sess->proxy_con->sock, sess->recv_raw)) {
34561 + case NETWORK_STATUS_SUCCESS:
34562 + /* we read everything from the socket, do we have a full header ? */
34564 + switch (proxy_parse_response_header(srv, con, p, sess, sess->recv_raw)) {
34565 + case PARSE_ERROR:
34566 + con->http_status = 502; /* bad gateway */
34568 + return HANDLER_FINISHED;
34569 + case PARSE_NEED_MORE:
34570 + /* we need more */
34571 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
34573 + return HANDLER_WAIT_FOR_EVENT;
34574 + case PARSE_SUCCESS:
34577 + return HANDLER_ERROR;
34580 + if (sess->do_internal_redirect) {
34581 + /* now it becomes tricky
34583 + * mod_staticfile should handle this file for us
34584 + * con->mode = DIRECT is taking us out of the loop */
34586 + return HANDLER_COMEBACK;
34589 + con->file_started = 1;
34590 + /* if Status: ... is not set, 200 is our default status-code */
34591 + if (con->http_status == 0) con->http_status = 200;
34593 + sess->state = PROXY_STATE_READ_RESPONSE_BODY;
34596 + * set the event to pass the content through to the server
34598 + * this triggers the event-handler
34599 + * @see proxy_handle_fdevent
34601 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
34603 + return HANDLER_GO_ON; /* tell http_response_prepare that we are done with the header */
34604 + case NETWORK_STATUS_WAIT_FOR_EVENT:
34605 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
34606 + return HANDLER_WAIT_FOR_EVENT;
34607 + case NETWORK_STATUS_CONNECTION_CLOSE:
34608 + if (chunkqueue_length(sess->recv_raw) == 0) {
34609 + /* the connection went away before we got something back */
34610 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
34613 + * we might run into a 'race-condition'
34615 + * 1. proxy-con is keep-alive, idling and just being closed (FDEVENT_IN) [fd=27]
34616 + * 2. new connection comes in, we use the idling connection [fd=14]
34617 + * 3. we write(), successful [to fd=27]
34618 + * 3. we read() ... and finally receive the close-event for the connection
34621 + ERROR("%s", "++ oops, connection closed while waiting to read a response, restarting");
34623 + return HANDLER_COMEBACK;
34626 + ERROR("%s", "conn-close after header-read");
34630 + ERROR("++ %s", "oops, something went wrong while reading");
34631 + return HANDLER_ERROR;
34633 + case PROXY_STATE_READ_RESPONSE_BODY:
34634 + /* if we do everything right, we won't get call for this state-anymore */
34636 + ERROR("%s", "PROXY_STATE_READ_RESPONSE_BODY");
34641 + return HANDLER_GO_ON;
34644 +proxy_backend *proxy_get_backend(server *srv, connection *con, plugin_data *p) {
34647 + for (i = 0; i < p->conf.backends->used; i++) {
34648 + proxy_backend *backend = p->conf.backends->ptr[i];
34657 + * choose a available address from the address-pool
34659 + * the backend has different balancers
34661 +proxy_address *proxy_backend_balance(server *srv, connection *con, proxy_backend *backend) {
34663 + proxy_address_pool *address_pool = backend->address_pool;
34664 + unsigned long last_max; /* for the HASH balancer */
34665 + proxy_address *address = NULL, *cur_address = NULL;
34666 + int active_addresses = 0, rand_ndx;
34668 + switch(backend->balancer) {
34669 + case PROXY_BALANCE_HASH:
34670 + /* hash balancing */
34672 + for (i = 0, last_max = ULONG_MAX; i < address_pool->used; i++) {
34673 + unsigned long cur_max;
34675 + cur_address = address_pool->ptr[i];
34677 + if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
34679 + cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
34680 + generate_crc32c(CONST_BUF_LEN(cur_address->name)) + /* we can cache this */
34681 + generate_crc32c(CONST_BUF_LEN(con->uri.authority));
34683 + TRACE("hash-election: %s - %s - %s: %ld",
34684 + con->uri.path->ptr,
34685 + cur_address->name->ptr,
34686 + con->uri.authority->ptr,
34689 + if (address == NULL || (cur_max > last_max)) {
34690 + last_max = cur_max;
34692 + address = cur_address;
34697 + case PROXY_BALANCE_FAIR:
34698 + /* fair balancing */
34700 + for (i = 0; i < address_pool->used; i++) {
34701 + cur_address = address_pool->ptr[i];
34703 + if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
34705 + /* the address is up, use it */
34707 + address = cur_address;
34713 + case PROXY_BALANCE_RR:
34714 + /* round robin */
34717 + * instead of real RoundRobin we just do a RandomSelect
34719 + * it is state-less and has the same distribution
34722 + active_addresses = 0;
34724 + for (i = 0; i < address_pool->used; i++) {
34725 + cur_address = address_pool->ptr[i];
34727 + if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
34729 + active_addresses++;
34732 + rand_ndx = (int) (1.0 * active_addresses * rand()/(RAND_MAX));
34734 + active_addresses = 0;
34735 + for (i = 0; i < address_pool->used; i++) {
34736 + cur_address = address_pool->ptr[i];
34738 + if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
34740 + address = cur_address;
34742 + if (rand_ndx == active_addresses++) break;
34753 +static int mod_proxy_core_patch_connection(server *srv, connection *con, plugin_data *p) {
34755 + plugin_config *s = p->config_storage[0];
34757 + /* global defaults */
34758 + PATCH_OPTION(balancer);
34759 + PATCH_OPTION(debug);
34760 + PATCH_OPTION(backends);
34761 + PATCH_OPTION(backlog);
34762 + PATCH_OPTION(protocol);
34763 + PATCH_OPTION(request_rewrites);
34764 + PATCH_OPTION(response_rewrites);
34765 + PATCH_OPTION(allow_x_sendfile);
34766 + PATCH_OPTION(allow_x_rewrite);
34768 + /* skip the first, the global context */
34769 + for (i = 1; i < srv->config_context->used; i++) {
34770 + data_config *dc = (data_config *)srv->config_context->data[i];
34771 + s = p->config_storage[i];
34773 + /* condition didn't match */
34774 + if (!config_check_cond(srv, con, dc)) continue;
34776 + /* merge config */
34777 + for (j = 0; j < dc->value->used; j++) {
34778 + data_unset *du = dc->value->data[j];
34780 + if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_BACKENDS))) {
34781 + PATCH_OPTION(backends);
34782 + PATCH_OPTION(backlog);
34783 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_DEBUG))) {
34784 + PATCH_OPTION(debug);
34785 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_BALANCER))) {
34786 + PATCH_OPTION(balancer);
34787 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_PROTOCOL))) {
34788 + PATCH_OPTION(protocol);
34789 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_REWRITE_REQUEST))) {
34790 + PATCH_OPTION(request_rewrites);
34791 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_REWRITE_RESPONSE))) {
34792 + PATCH_OPTION(response_rewrites);
34793 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_ALLOW_X_SENDFILE))) {
34794 + PATCH_OPTION(allow_x_sendfile);
34795 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_ALLOW_X_REWRITE))) {
34796 + PATCH_OPTION(allow_x_rewrite);
34804 +SUBREQUEST_FUNC(mod_proxy_core_check_extension) {
34805 + plugin_data *p = p_d;
34806 + proxy_session *sess = con->plugin_ctx[p->id]; /* if this is the second round, sess is already prepared */
34808 + /* check if we have a matching conditional for this request */
34810 + if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
34812 + mod_proxy_core_patch_connection(srv, con, p);
34814 + if (p->conf.backends->used == 0) return HANDLER_GO_ON;
34817 + /* a session lives for a single request */
34818 + sess = proxy_session_init();
34820 + con->plugin_ctx[p->id] = sess;
34821 + con->mode = p->id;
34823 + sess->remote_con = con;
34826 + return HANDLER_GO_ON;
34829 +CONNECTION_FUNC(mod_proxy_core_start_backend) {
34830 + plugin_data *p = p_d;
34831 + proxy_session *sess = con->plugin_ctx[p->id];
34833 + if (p->id != con->mode) return HANDLER_GO_ON;
34836 + * 0. build session
34837 + * 1. get a proxy connection
34838 + * 2. create the http-request header
34839 + * 3. stream the content to the backend
34840 + * 4. wait for http-response header
34841 + * 5. decode the response + parse the response
34842 + * 6. stream the response-content to the client
34843 + * 7. kill session
34849 + if (sess->do_internal_redirect) {
34850 + if (sess->internal_redirect_count > MAX_INTERNAL_REDIRECTS) {
34851 + /* we already handled this request and sent it to the static file handling */
34853 + return HANDLER_GO_ON;
34857 + switch (sess->state) {
34858 + case PROXY_STATE_CONNECTING:
34859 + /* this connections is waited 10 seconds to connect to the backend
34860 + * and didn't got a successful connection yet, sending timeout */
34861 + if (srv->cur_ts - sess->connect_start_ts > 10) {
34862 + con->http_status = 504; /* gateway timeout */
34863 + con->send->is_closed = 1;
34865 + if (sess->proxy_con) {
34866 + /* if we are waiting for a proxy-connection right now, close it */
34867 + proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
34869 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
34870 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
34872 + proxy_connection_free(sess->proxy_con);
34874 + sess->proxy_con = NULL;
34877 + TRACE("%s", "connect to backend timed out");
34879 + return HANDLER_FINISHED;
34882 + /* handle-request-timeout, */
34884 + if (srv->cur_ts - con->request_start > 60) {
34885 + TRACE("request runs longer than 60sec: current state: %d", sess->state);
34891 + /* if the WRITE fails from the start, restart the connection */
34893 + if (sess->proxy_con == NULL) {
34894 + proxy_address *address = NULL;
34895 + if (NULL == (sess->proxy_backend = proxy_get_backend(srv, con, p))) {
34896 + /* no connection pool for this location */
34900 + sess->proxy_backend->balancer = p->conf.balancer;
34901 + sess->proxy_backend->protocol = p->conf.protocol;
34904 + * ask the balancer for the next address and
34905 + * check the connection pool if we have a connection open
34906 + * for that address
34908 + if (NULL == (address = proxy_backend_balance(srv, con, sess->proxy_backend))) {
34909 + /* we don't have any backends to connect to */
34910 + proxy_request *req;
34912 + /* connection pool is full, queue the request for now */
34913 + req = proxy_request_init();
34914 + req->added_ts = srv->cur_ts;
34917 + TRACE("backlog: all backends are down, putting %s (%d) into the backlog", BUF_STR(con->uri.path), con->sock->fd);
34918 + proxy_backlog_push(p->conf.backlog, req);
34920 + /* no, not really a event,
34921 + * we just want to block the outer loop from stepping forward
34923 + * the trigger will bring this connection back into the game
34925 + return HANDLER_WAIT_FOR_EVENT;
34928 + if (PROXY_CONNECTIONPOOL_FULL == proxy_connection_pool_get_connection(
34929 + sess->proxy_backend->pool,
34931 + &(sess->proxy_con))) {
34932 + proxy_request *req;
34934 + /* connection pool is full, queue the request for now */
34935 + req = proxy_request_init();
34936 + req->added_ts = srv->cur_ts;
34940 + TRACE("backlog: the con-pool is full, putting %s (%d) into the backlog", BUF_STR(con->uri.path), con->sock->fd);
34942 + proxy_backlog_push(p->conf.backlog, req);
34944 + /* no, not really a event,
34945 + * we just want to block the outer loop from stepping forward
34947 + * the trigger will bring this connection back into the game
34949 + return HANDLER_WAIT_FOR_EVENT;
34952 + /* a fresh connection, we need address for it */
34953 + if (sess->proxy_con->state == PROXY_CONNECTION_STATE_CONNECTING) {
34954 + sess->state = PROXY_STATE_UNSET;
34955 + sess->bytes_read = 0;
34957 + /* we are already connected */
34958 + sess->state = PROXY_STATE_CONNECTED;
34960 + /* the connection was idling and using the fdevent_idle-handler
34961 + * switch it back to the normal proxy-event-handler */
34962 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
34963 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
34965 + fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
34966 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
34970 + switch (proxy_state_engine(srv, con, p, sess)) {
34971 + case HANDLER_WAIT_FOR_EVENT:
34972 + return HANDLER_WAIT_FOR_EVENT;
34973 + case HANDLER_COMEBACK:
34974 + proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
34976 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
34977 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
34979 + proxy_connection_free(sess->proxy_con);
34981 + sess->proxy_con = NULL;
34983 + if (sess->do_internal_redirect) {
34984 + con->mode = DIRECT;
34985 + con->http_status = 0;
34987 + return HANDLER_COMEBACK;
34989 + /* restart the connection to the backend */
34990 + TRACE("%s", "write failed, restarting request");
34992 + case HANDLER_GO_ON:
34993 + return HANDLER_GO_ON;
34995 + TRACE("state: %d (error)", sess->state);
34996 + return HANDLER_ERROR;
35000 + TRACE("state: %d", sess->state);
35001 + /* should not be reached */
35002 + return HANDLER_ERROR;
35005 +CONNECTION_FUNC(mod_proxy_send_request_content) {
35006 + plugin_data *p = p_d;
35007 + proxy_session *sess = con->plugin_ctx[p->id];
35009 + if (p->id != con->mode) return HANDLER_GO_ON;
35011 + /* read all the content before we start our backend */
35012 + if (!con->recv->is_closed) {
35013 + return HANDLER_GO_ON;
35016 + /* copy the chunks to our queue and call the state-engine to send it out */
35017 + return mod_proxy_core_start_backend(srv, con, p_d);
35020 + * end of the connection to the client
35022 +REQUESTDONE_FUNC(mod_proxy_connection_close_callback) {
35023 + plugin_data *p = p_d;
35025 + if (con->mode != p->id) return HANDLER_GO_ON;
35027 + return HANDLER_GO_ON;
35031 + * end of a request
35033 +CONNECTION_FUNC(mod_proxy_connection_reset) {
35034 + plugin_data *p = p_d;
35035 + proxy_session *sess = con->plugin_ctx[p->id];
35036 + proxy_request *req;
35038 + if (!sess) return HANDLER_GO_ON;
35040 + if (sess->proxy_con) {
35041 + switch (sess->proxy_con->state) {
35042 + case PROXY_CONNECTION_STATE_CONNECTED:
35043 + if (!sess->is_closing) {
35044 + sess->proxy_con->state = PROXY_CONNECTION_STATE_IDLE;
35046 + /* don't ignore events as the FD is idle
35047 + * we might get a HUP as the remote connection might close */
35048 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
35049 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
35051 + fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent_idle, sess->proxy_con);
35052 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
35057 + /* fall-through for non-keep-alive */
35059 + case PROXY_CONNECTION_STATE_CLOSED:
35060 + proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
35062 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
35063 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
35065 + proxy_connection_free(sess->proxy_con);
35067 + case PROXY_CONNECTION_STATE_IDLE:
35068 + TRACE("%s", "... connection is already back in the pool");
35071 + ERROR("connection is in a unexpected state at close-time: %d", sess->proxy_con->state);
35075 + /* if we have the connection in the backlog, remove it */
35076 + proxy_backlog_remove_connection(p->conf.backlog, con);
35080 + proxy_session_free(sess);
35082 + con->plugin_ctx[p->id] = NULL;
35084 + /* wake up a connection from the backlog */
35085 + if ((req = proxy_backlog_shift(p->conf.backlog))) {
35086 + connection *next_con = req->con;
35088 + joblist_append(srv, next_con);
35090 + proxy_request_free(req);
35094 + return HANDLER_GO_ON;
35100 + * cleanup dead connections once a second
35102 + * the idling event-handler can't cleanup connections itself and has to wait until the
35103 + * trigger cleans up
35105 +handler_t mod_proxy_trigger_context(server *srv, plugin_config *p) {
35107 + proxy_request *req;
35109 + for (i = 0; i < p->backends->used; i++) {
35110 + proxy_backend *backend = p->backends->ptr[i];
35111 + proxy_connection_pool *pool = backend->pool;
35112 + proxy_address_pool *address_pool = backend->address_pool;
35114 + for (j = 0; j < pool->used; ) {
35115 + proxy_connection *proxy_con = pool->ptr[j];
35117 + /* remove-con is removing the current con and moves the good connections to the left
35118 + * no need to increment i */
35119 + if (proxy_con->state == PROXY_CONNECTION_STATE_CLOSED) {
35120 + proxy_connection_pool_remove_connection(backend->pool, proxy_con);
35122 + fdevent_event_del(srv->ev, proxy_con->sock);
35123 + fdevent_unregister(srv->ev, proxy_con->sock);
35125 + proxy_connection_free(proxy_con);
35131 + /* active the disabled addresses again */
35132 + for (j = 0; j < address_pool->used; j++) {
35133 + proxy_address *address = address_pool->ptr[j];
35135 + if (address->state != PROXY_ADDRESS_STATE_DISABLED) continue;
35137 + if (srv->cur_ts > address->disabled_until) {
35138 + address->disabled_until = 0;
35139 + address->state = PROXY_ADDRESS_STATE_ACTIVE;
35144 + /* wake up the connections from the backlog */
35145 + while ((req = proxy_backlog_shift(p->backlog))) {
35146 + connection *con = req->con;
35148 + joblist_append(srv, con);
35150 + proxy_request_free(req);
35153 + return HANDLER_GO_ON;
35156 +TRIGGER_FUNC(mod_proxy_trigger) {
35157 + plugin_data *p = p_d;
35160 + for (i = 0; i < srv->config_context->used; i++) {
35161 + mod_proxy_trigger_context(srv, p->config_storage[i]);
35164 + return HANDLER_GO_ON;
35167 +int mod_proxy_core_plugin_init(plugin *p) {
35168 + p->version = LIGHTTPD_VERSION_ID;
35169 + p->name = buffer_init_string("mod_proxy_core");
35171 + p->init = mod_proxy_core_init;
35172 + p->cleanup = mod_proxy_core_free;
35173 + p->set_defaults = mod_proxy_core_set_defaults;
35174 + p->handle_physical = mod_proxy_core_check_extension;
35175 + p->handle_send_request_content = mod_proxy_send_request_content;
35176 + p->connection_reset = mod_proxy_connection_reset;
35177 + p->handle_connection_close = mod_proxy_connection_close_callback;
35178 + p->handle_trigger = mod_proxy_trigger;
35184 --- ../lighttpd-1.4.11/src/mod_proxy_core.h 1970-01-01 03:00:00.000000000 +0300
35185 +++ lighttpd-1.5.0/src/mod_proxy_core.h 2006-09-07 00:57:05.000000000 +0300
35187 +#ifndef _MOD_PROXY_CORE_H_
35188 +#define _MOD_PROXY_CORE_H_
35190 +#include "buffer.h"
35191 +#include "plugin.h"
35192 +#include "http_resp.h"
35193 +#include "array.h"
35195 +#include "mod_proxy_core_pool.h"
35196 +#include "mod_proxy_core_backend.h"
35197 +#include "mod_proxy_core_backlog.h"
35198 +#include "mod_proxy_core_rewrites.h"
35200 +#define MAX_INTERNAL_REDIRECTS 8
35203 + proxy_backends *backends;
35205 + proxy_backlog *backlog;
35207 + proxy_rewrites *request_rewrites;
35208 + proxy_rewrites *response_rewrites;
35210 + unsigned short allow_x_sendfile;
35211 + unsigned short allow_x_rewrite;
35212 + unsigned short debug;
35213 + unsigned short max_pool_size;
35215 + proxy_balance_t balancer;
35216 + proxy_protocol_t protocol;
35224 + array *possible_balancers;
35225 + array *possible_protocols;
35227 + /* for parsing only */
35228 + array *backends_arr;
35229 + buffer *protocol_buf;
35230 + buffer *balance_buf;
35232 + buffer *replace_buf;
35234 + buffer *tmp_buf; /** a temporary buffer, used by mod_proxy_backend_fastcgi */
35236 + plugin_config **config_storage;
35238 + plugin_config conf;
35243 + PROXY_STATE_UNSET,
35244 + PROXY_STATE_CONNECTING,
35245 + PROXY_STATE_CONNECTED,
35246 + PROXY_STATE_WRITE_REQUEST_HEADER,
35247 + PROXY_STATE_WRITE_REQUEST_BODY,
35248 + PROXY_STATE_READ_RESPONSE_HEADER,
35249 + PROXY_STATE_READ_RESPONSE_BODY
35253 + proxy_connection *proxy_con;
35254 + proxy_backend *proxy_backend;
35256 + connection *remote_con;
35258 + array *request_headers; /** the con->request.headers without the hop-to-hop headers */
35259 + array *env_headers; /** transformed request-headers for the backend */
35261 + int is_chunked; /** is the incoming content chunked (for HTTP) */
35262 + int is_closing; /** our connection will close when we are done */
35263 + int send_response_content; /** 0 if we have to ignore the content-body */
35264 + int do_internal_redirect; /** 1 if we do a internal redirect to the ->mode = DIRECT */
35265 + int internal_redirect_count; /** protection against infinite loops */
35269 + * - the encoded_rb is the raw network stuff
35270 + * - the rb is filtered through the stream decoder
35272 + * - wb is the normal bytes stream
35273 + * - encoded_wb is encoded for the network by the stream encoder
35275 + chunkqueue *recv;
35276 + chunkqueue *recv_raw;
35277 + chunkqueue *send_raw;
35278 + chunkqueue *send;
35280 + off_t bytes_read;
35281 + off_t content_length;
35283 + proxy_state_t state;
35285 + time_t connect_start_ts;
35288 +void proxy_set_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len);
35291 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.c 1970-01-01 03:00:00.000000000 +0300
35292 +++ lighttpd-1.5.0/src/mod_proxy_core_address.c 2006-07-20 00:57:20.000000000 +0300
35294 +#include <stdlib.h>
35295 +#include <string.h>
35298 +#include "sys-socket.h"
35299 +#include "mod_proxy_core_address.h"
35301 +proxy_address *proxy_address_init(void) {
35302 + proxy_address *address;
35304 + address = calloc(1, sizeof(*address));
35306 + address->name = buffer_init();
35311 +void proxy_address_free(proxy_address *address) {
35312 + if (!address) return;
35314 + buffer_free(address->name);
35320 +proxy_address_pool *proxy_address_pool_init(void) {
35321 + proxy_address_pool *address_pool;
35323 + address_pool = calloc(1, sizeof(*address_pool));
35325 + return address_pool;
35328 +void proxy_address_pool_free(proxy_address_pool *address_pool) {
35329 + if (!address_pool) return;
35331 + FOREACH(address_pool, element, proxy_address_free(element));
35333 + if (address_pool->ptr) free(address_pool->ptr);
35335 + free(address_pool);
35338 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address) {
35341 + /* check if this address is already known */
35343 + for (i = 0; i < address_pool->used; i++) {
35344 + proxy_address *pool_address = address_pool->ptr[i];
35346 + if (buffer_is_equal(address->name, pool_address->name)) {
35347 + TRACE("%s is already in the address-pool", BUF_STR(address->name));
35349 + proxy_address_free(address);
35355 + TRACE("adding %s to the address-pool", BUF_STR(address->name));
35357 + ARRAY_STATIC_PREPARE_APPEND(address_pool);
35359 + address_pool->ptr[address_pool->used++] = address;
35362 +int proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *name) {
35363 + struct addrinfo *res = NULL, pref, *cur;
35365 + buffer *hostname = NULL, *port = NULL;
35368 + pref.ai_flags = 0;
35369 + pref.ai_family = PF_UNSPEC;
35370 + pref.ai_socktype = SOCK_STREAM;
35371 + pref.ai_protocol = 0;
35372 + pref.ai_addrlen = 0;
35373 + pref.ai_addr = NULL;
35374 + pref.ai_canonname = NULL;
35375 + pref.ai_next = NULL;
35377 + /* check the address style
35379 + * unix:/tmp/socket
35380 + * www.example.org
35381 + * www.example.org:80
35388 + if (buffer_is_empty(name)) return -1;
35390 + if (0 == strncmp(BUF_STR(name), "unix:", 5)) {
35391 + /* a unix domain socket */
35392 + ERROR("unix: scheme is not supported for %s", BUF_STR(name));
35394 + } else if (name->ptr[0] == '[') {
35395 + if (name->ptr[name->used - 1] == ']') {
35396 + /* no port-number attached */
35398 + hostname = buffer_init();
35399 + buffer_copy_string_len(hostname, BUF_STR(name) + 1, name->used - 3);
35400 + port = buffer_init_string("80");
35401 + } else if (NULL != (colon = strrchr(BUF_STR(name), ':'))) {
35402 + /* with port number */
35404 + hostname = buffer_init();
35405 + buffer_copy_string_len(hostname, BUF_STR(name) + 1, colon - BUF_STR(name) - 2);
35406 + port = buffer_init();
35407 + buffer_copy_string(port, colon + 1);
35410 + ERROR("this is neither [<ipv6-address>] nor [<ipv6-address>]:<port>: %s", BUF_STR(name));
35414 + } else if (name->ptr[name->used - 1] != ']' &&
35415 + NULL != (colon = strrchr(BUF_STR(name), ':'))) {
35417 + hostname = buffer_init();
35418 + buffer_copy_string_len(hostname, BUF_STR(name), colon - BUF_STR(name));
35419 + port = buffer_init();
35420 + buffer_copy_string(port, colon + 1);
35422 + /* no colon, just a IPv4 address or a domain name */
35424 + hostname = buffer_init_string(BUF_STR(name));
35425 + port = buffer_init_string("80");
35428 + TRACE("resolving %s on port %s", BUF_STR(hostname), BUF_STR(port));
35430 + if (0 != (ret = getaddrinfo(BUF_STR(hostname), BUF_STR(port), &pref, &res))) {
35431 + ERROR("getaddrinfo failed: %s", gai_strerror(ret));
35433 + buffer_free(hostname);
35434 + buffer_free(port);
35439 + buffer_free(hostname);
35440 + buffer_free(port);
35442 + for (cur = res; cur; cur = cur->ai_next) {
35443 + proxy_address *a = proxy_address_init();
35445 + memcpy(&(a->addr), cur->ai_addr, cur->ai_addrlen);
35447 + a->state = PROXY_ADDRESS_STATE_ACTIVE;
35448 + buffer_prepare_copy(a->name, 128);
35450 + switch (cur->ai_family) {
35452 + a->name->ptr[0] = '[';
35453 + inet_ntop(cur->ai_family, &(a->addr.ipv6.sin6_addr), a->name->ptr + 1, a->name->size - 2);
35454 + a->name->used = strlen(a->name->ptr) + 1;
35455 + buffer_append_string(a->name, "]:");
35456 + buffer_append_long(a->name, ntohs(a->addr.ipv6.sin6_port));
35459 + inet_ntop(cur->ai_family, &(a->addr.ipv4.sin_addr), a->name->ptr, a->name->size - 1);
35460 + a->name->used = strlen(a->name->ptr) + 1;
35462 + buffer_append_string(a->name, ":");
35463 + buffer_append_long(a->name, ntohs(a->addr.ipv4.sin_port));
35466 + ERROR("unknown address-family: %d", cur->ai_family);
35471 + proxy_address_pool_add(address_pool, a);
35474 + freeaddrinfo(res);
35480 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.h 1970-01-01 03:00:00.000000000 +0300
35481 +++ lighttpd-1.5.0/src/mod_proxy_core_address.h 2006-07-18 13:03:40.000000000 +0300
35483 +#ifndef _MOD_PROXY_CORE_ADDRESS_H_
35484 +#define _MOD_PROXY_CORE_ADDRESS_H_
35487 +#include "buffer.h"
35488 +#include "sys-socket.h"
35489 +#include "array-static.h"
35492 + PROXY_ADDRESS_STATE_UNSET,
35493 + PROXY_ADDRESS_STATE_ACTIVE,
35494 + PROXY_ADDRESS_STATE_DISABLED,
35495 +} proxy_address_state_t;
35500 + buffer *name; /* a inet_ntoa() prepresentation of the address */
35502 + time_t last_used;
35503 + time_t disabled_until;
35505 + proxy_address_state_t state;
35508 +ARRAY_STATIC_DEF(proxy_address_pool, proxy_address, );
35510 +proxy_address_pool *proxy_address_pool_init(void);
35511 +void proxy_address_pool_free(proxy_address_pool *address_pool);
35512 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address);
35513 +int proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *address);
35516 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.c 1970-01-01 03:00:00.000000000 +0300
35517 +++ lighttpd-1.5.0/src/mod_proxy_core_backend.c 2006-07-20 00:57:19.000000000 +0300
35519 +#include <stdlib.h>
35521 +#include "mod_proxy_core_backend.h"
35522 +#include "mod_proxy_core_pool.h"
35523 +#include "mod_proxy_core_address.h"
35525 +proxy_backend *proxy_backend_init(void) {
35526 + proxy_backend *backend;
35528 + backend = calloc(1, sizeof(*backend));
35529 + backend->pool = proxy_connection_pool_init();
35530 + backend->address_pool = proxy_address_pool_init();
35531 + backend->balancer = PROXY_BALANCE_RR;
35536 +void proxy_backend_free(proxy_backend *backend) {
35537 + if (!backend) return;
35539 + proxy_address_pool_free(backend->address_pool);
35540 + proxy_connection_pool_free(backend->pool);
35545 +proxy_backends *proxy_backends_init(void) {
35546 + proxy_backends *backends;
35548 + backends = calloc(1, sizeof(*backends));
35553 +void proxy_backends_free(proxy_backends *backends) {
35554 + FOREACH(backends, element, proxy_backend_free(element))
35556 + if (backends->ptr) free(backends->ptr);
35561 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend) {
35562 + ARRAY_STATIC_PREPARE_APPEND(backends);
35564 + backends->ptr[backends->used++] = backend;
35566 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.h 1970-01-01 03:00:00.000000000 +0300
35567 +++ lighttpd-1.5.0/src/mod_proxy_core_backend.h 2006-09-07 00:57:05.000000000 +0300
35569 +#ifndef _MOD_PROXY_CORE_BACKEND_H_
35570 +#define _MOD_PROXY_CORE_BACKEND_H_
35572 +#include "array-static.h"
35573 +#include "buffer.h"
35574 +#include "mod_proxy_core_address.h"
35575 +#include "mod_proxy_core_pool.h"
35576 +#include "sys-socket.h"
35579 + * a single DNS name might explode to several IP addresses
35582 + * - http://foo.bar/suburl/
35583 + * - https://foo.bar/suburl/
35584 + * - unix:/tmp/socket
35585 + * - tcp://foobar:1025/
35592 + * request-url-rewrite
35593 + * response-url-rewrite
35596 + PROXY_BALANCE_UNSET,
35597 + PROXY_BALANCE_FAIR,
35598 + PROXY_BALANCE_HASH,
35600 +} proxy_balance_t;
35603 + PROXY_PROTOCOL_UNSET,
35604 + PROXY_PROTOCOL_HTTP,
35605 + PROXY_PROTOCOL_HTTPS,
35606 + PROXY_PROTOCOL_FASTCGI,
35607 + PROXY_PROTOCOL_SCGI
35608 +} proxy_protocol_t;
35613 + proxy_connection_pool *pool; /* pool of active connections */
35614 + int use_keepalive;
35616 + proxy_address_pool *address_pool; /* possible destination-addresses, disabling is done here */
35617 + proxy_balance_t balancer; /* how to choose a address from the address-pool */
35618 + proxy_protocol_t protocol; /* how to choose a address from the address-pool */
35621 +ARRAY_STATIC_DEF(proxy_backends, proxy_backend, );
35623 +proxy_backend *proxy_backend_init(void);
35624 +void proxy_backend_free(proxy_backend *backend);
35626 +proxy_backends *proxy_backends_init(void);
35627 +void proxy_backends_free(proxy_backends *backends);
35628 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend);
35632 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.c 1970-01-01 03:00:00.000000000 +0300
35633 +++ lighttpd-1.5.0/src/mod_proxy_core_backlog.c 2006-07-18 13:03:40.000000000 +0300
35635 +#include <stdlib.h>
35637 +#include "mod_proxy_core_backlog.h"
35638 +#include "array-static.h"
35640 +proxy_backlog *proxy_backlog_init(void) {
35641 + STRUCT_INIT(proxy_backlog, backlog);
35646 +void proxy_backlog_free(proxy_backlog *backlog) {
35647 + if (!backlog) return;
35652 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req) {
35653 + /* first entry */
35654 + if (NULL == backlog->first) {
35655 + backlog->first = backlog->last = req;
35657 + backlog->last->next = req;
35658 + backlog->last = req;
35660 + backlog->length++;
35666 + * remove the first element from the backlog
35668 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog) {
35669 + proxy_request *req = NULL;
35671 + if (!backlog->first) return req;
35673 + backlog->length--;
35675 + req = backlog->first;
35677 + backlog->first = req->next;
35679 + /* the backlog is empty */
35680 + if (backlog->first == NULL) backlog->last = NULL;
35685 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con) {
35686 + proxy_request *req = NULL;
35688 + if (!backlog->first) return -1;
35689 + if (!con) return -1;
35691 + /* the first element is what we look for */
35692 + if (backlog->first->con == con) {
35693 + req = backlog->first;
35695 + backlog->first = req->next;
35696 + if (backlog->first == NULL) backlog->last = NULL;
35698 + backlog->length--;
35700 + proxy_request_free(req);
35706 + for (req = backlog->first; req && req->next; req = req->next) {
35707 + proxy_request *cur;
35709 + if (req->next->con != con) continue;
35711 + backlog->length--;
35712 + /* the next node is our searched connection */
35715 + req->next = cur->next;
35717 + /* the next node is the last one, make the current the new last */
35718 + if (cur == backlog->last) {
35719 + backlog->last = req;
35721 + cur->next = NULL;
35723 + proxy_request_free(req);
35731 +proxy_request *proxy_request_init(void) {
35732 + STRUCT_INIT(proxy_request, request);
35737 +void proxy_request_free(proxy_request *request) {
35738 + if (!request) return;
35744 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.h 1970-01-01 03:00:00.000000000 +0300
35745 +++ lighttpd-1.5.0/src/mod_proxy_core_backlog.h 2006-07-18 13:03:40.000000000 +0300
35747 +#ifndef _MOD_PROXY_CORE_BACKLOG_H_
35748 +#define _MOD_PROXY_CORE_BACKLOG_H_
35750 +#include <sys/types.h>
35751 +#include <sys/time.h>
35753 +typedef struct _proxy_request {
35754 + void *con; /* a pointer to the client-connection, (type: connection) */
35756 + time_t added_ts; /* when was the entry added (for timeout handling) */
35758 + struct _proxy_request *next;
35762 + * a we can't get a connection from the pool, queue the request in the
35763 + * request queue (FIFO)
35765 + * - the queue is infinite
35766 + * - entries are removed after a timeout (status 504)
35769 + proxy_request *first; /* pull() does q->first = q->first->next */
35770 + proxy_request *last; /* push() does q->last = r */
35775 +proxy_backlog *proxy_backlog_init(void);
35776 +void proxy_backlog_free(proxy_backlog *backlog);
35779 + * append a request to the end
35781 + * @return 0 in success, -1 if full
35783 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req);
35786 + * remove the first request from the backlog
35788 + * @return NULL if backlog is empty, the request otherwise
35790 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog);
35792 + * remove the request with the connection 'con' from the backlog
35794 + * @return -1 if not found, 0 otherwise
35796 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con);
35798 +proxy_request *proxy_request_init(void);
35799 +void proxy_request_free(proxy_request *req);
35803 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.c 1970-01-01 03:00:00.000000000 +0300
35804 +++ lighttpd-1.5.0/src/mod_proxy_core_pool.c 2006-07-18 13:03:40.000000000 +0300
35807 +#include <stdlib.h>
35809 +#include "array-static.h"
35810 +#include "sys-files.h"
35812 +#include "mod_proxy_core_pool.h"
35814 +proxy_connection * proxy_connection_init(void) {
35815 + proxy_connection *con;
35817 + con = calloc(1, sizeof(*con));
35819 + con->sock = iosocket_init();
35824 +void proxy_connection_free(proxy_connection *con) {
35825 + if (!con) return;
35827 + iosocket_free(con->sock);
35832 +proxy_connection_pool *proxy_connection_pool_init(void) {
35833 + proxy_connection_pool *pool;
35835 + pool = calloc(1, sizeof(*pool));
35837 + /* default: max parallel connections to the backend
35839 + * this should match max-procs if we manage the procs ourself
35842 + pool->max_size = 8;
35847 +void proxy_connection_pool_free(proxy_connection_pool *pool) {
35850 + if (!pool) return;
35852 + for (i = 0; i < pool->used; i++) {
35853 + proxy_connection_free(pool->ptr[i]);
35856 + if (pool->size) free(pool->ptr);
35861 +void proxy_connection_pool_add_connection(proxy_connection_pool *pool, proxy_connection *c) {
35862 + ARRAY_STATIC_PREPARE_APPEND(pool);
35864 + pool->ptr[pool->used++] = c;
35867 + * remove the connection from the pool
35869 + * usually called on conn-shutdown
35871 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c) {
35874 + if (pool->used == 0) return -1; /* empty */
35876 + for (i = 0; i < pool->used; i++) {
35877 + if (pool->ptr[i] == c) {
35882 + if (i == pool->used) return -1; /* not found */
35885 + * move all elements one to the left
35887 + * if the last element is going to be removed, skip the loop
35889 + for (; i < pool->used - 1; i++) {
35890 + pool->ptr[i] = pool->ptr[i + 1];
35898 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon) {
35899 + proxy_connection *proxy_con = NULL;
35902 + /* search for a idling proxy connection with the given address */
35903 + for (i = 0; i < pool->used; i++) {
35904 + proxy_con = pool->ptr[i];
35906 + if (proxy_con->address == address &&
35907 + proxy_con->state == PROXY_CONNECTION_STATE_IDLE) {
35912 + if (i == pool->used) {
35913 + /* no idling connection found */
35915 + if (pool->used == pool->max_size) return PROXY_CONNECTIONPOOL_FULL;
35917 + proxy_con = proxy_connection_init();
35919 + proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
35920 + proxy_con->address = address;
35922 + proxy_connection_pool_add_connection(pool, proxy_con);
35924 + proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
35927 + *rcon = proxy_con;
35929 + return PROXY_CONNECTIONPOOL_GOT_CONNECTION;
35933 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.h 1970-01-01 03:00:00.000000000 +0300
35934 +++ lighttpd-1.5.0/src/mod_proxy_core_pool.h 2006-07-18 13:03:40.000000000 +0300
35936 +#ifndef _MOD_PROXY_CORE_POOL_H_
35937 +#define _MOD_PROXY_CORE_POOL_H_
35939 +#include <sys/time.h>
35941 +#include "iosocket.h"
35942 +#include "array-static.h"
35943 +#include "mod_proxy_core_address.h"
35946 + PROXY_CONNECTION_STATE_UNSET,
35947 + PROXY_CONNECTION_STATE_CONNECTING,
35948 + PROXY_CONNECTION_STATE_CONNECTED,
35949 + PROXY_CONNECTION_STATE_IDLE,
35950 + PROXY_CONNECTION_STATE_CLOSED,
35951 +} proxy_connection_state_t;
35954 + * a connection to a proxy backend
35956 + * the connection is independent of the incoming request to allow keep-alive
35961 + time_t last_read; /* timeout handling for keep-alive connections */
35962 + time_t last_write;
35964 + proxy_address *address; /* the struct sock_addr for the sock */
35966 + proxy_connection_state_t state;
35967 +} proxy_connection;
35969 +ARRAY_STATIC_DEF(proxy_connection_pool, proxy_connection, size_t max_size;);
35972 + PROXY_CONNECTIONPOOL_UNSET,
35973 + PROXY_CONNECTIONPOOL_FULL,
35974 + PROXY_CONNECTIONPOOL_GOT_CONNECTION,
35975 +} proxy_connection_pool_t;
35977 +proxy_connection_pool *proxy_connection_pool_init(void);
35978 +void proxy_connection_pool_free(proxy_connection_pool *pool);
35980 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon);
35981 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c);
35983 +proxy_connection * proxy_connection_init(void);
35984 +void proxy_connection_free(proxy_connection *pool);
35988 --- ../lighttpd-1.4.11/src/mod_proxy_core_rewrites.c 1970-01-01 03:00:00.000000000 +0300
35989 +++ lighttpd-1.5.0/src/mod_proxy_core_rewrites.c 2006-09-07 00:57:05.000000000 +0300
35991 +#include <stdlib.h>
35992 +#include <string.h>
35993 +#include <ctype.h>
35995 +#include "mod_proxy_core_rewrites.h"
35998 +proxy_rewrite *proxy_rewrite_init(void) {
35999 + STRUCT_INIT(proxy_rewrite, rewrite);
36001 + rewrite->header = buffer_init();
36002 + rewrite->match = buffer_init();
36003 + rewrite->replace = buffer_init();
36008 +void proxy_rewrite_free(proxy_rewrite *rewrite) {
36009 + if (!rewrite) return;
36011 + if (rewrite->regex) pcre_free(rewrite->regex);
36013 + buffer_free(rewrite->header);
36014 + buffer_free(rewrite->match);
36015 + buffer_free(rewrite->replace);
36020 +int proxy_rewrite_set_regex(proxy_rewrite *rewrite, buffer *regex) {
36021 + const char *errptr;
36024 + if (NULL == (rewrite->regex = pcre_compile(BUF_STR(regex),
36025 + 0, &errptr, &erroff, NULL))) {
36027 + TRACE("regex compilation for %s failed at %s", BUF_STR(regex), errptr);
36036 +proxy_rewrites *proxy_rewrites_init(void) {
36037 + STRUCT_INIT(proxy_rewrites, rewrites);
36042 +void proxy_rewrites_add(proxy_rewrites *rewrites, proxy_rewrite *rewrite) {
36043 + ARRAY_STATIC_PREPARE_APPEND(rewrites);
36045 + rewrites->ptr[rewrites->used++] = rewrite;
36048 +void proxy_rewrites_free(proxy_rewrites *rewrites) {
36049 + if (!rewrites) return;
36051 + FOREACH(rewrites, rewrite, proxy_rewrite_free(rewrite))
36053 + if (rewrites->ptr) free(rewrites->ptr);
36058 +int pcre_replace(pcre *match, buffer *replace, buffer *match_buf, buffer *result) {
36059 + const char *pattern = replace->ptr;
36060 + size_t pattern_len = replace->used - 1;
36066 + if ((n = pcre_exec(match, NULL, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
36067 + if (n != PCRE_ERROR_NOMATCH) {
36071 + const char **list;
36072 + size_t start, end;
36076 + pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
36078 + /* search for $[0-9] */
36080 + buffer_reset(result);
36082 + start = 0; end = pattern_len;
36083 + for (k = 0; k < pattern_len; k++) {
36084 + if ((pattern[k] == '$') &&
36085 + isdigit((unsigned char)pattern[k + 1])) {
36088 + size_t num = pattern[k + 1] - '0';
36092 + buffer_append_string_len(result, pattern + start, end - start);
36094 + /* n is always > 0 */
36095 + if (num < (size_t)n) {
36096 + buffer_append_string(result, list[num]);
36104 + buffer_append_string_len(result, pattern + start, pattern_len - start);
36113 --- ../lighttpd-1.4.11/src/mod_proxy_core_rewrites.h 1970-01-01 03:00:00.000000000 +0300
36114 +++ lighttpd-1.5.0/src/mod_proxy_core_rewrites.h 2006-09-07 00:57:05.000000000 +0300
36116 +#ifndef _MOD_PROXY_CORE_REWRITES_H_
36117 +#define _MOD_PROXY_CORE_REWRITES_H_
36120 +#include "array-static.h"
36121 +#include "buffer.h"
36126 + pcre *regex; /* regex compiled from the <match> */
36132 +ARRAY_STATIC_DEF(proxy_rewrites, proxy_rewrite,);
36134 +proxy_rewrite *proxy_rewrite_init(void);
36135 +void proxy_rewrite_free(proxy_rewrite *rewrite);
36136 +int proxy_rewrite_set_regex(proxy_rewrite *rewrite, buffer *regex);
36138 +proxy_rewrites *proxy_rewrites_init(void);
36139 +void proxy_rewrites_add(proxy_rewrites *rewrites, proxy_rewrite *rewrite);
36140 +void proxy_rewrites_free(proxy_rewrites *rewrites);
36142 +int pcre_replace(pcre *match, buffer *replace, buffer *match_buf, buffer *result);
36146 --- ../lighttpd-1.4.11/src/mod_redirect.c 2006-02-08 15:38:06.000000000 +0200
36147 +++ lighttpd-1.5.0/src/mod_redirect.c 2006-09-07 00:57:05.000000000 +0300
36148 @@ -22,35 +22,35 @@
36154 plugin_config **config_storage;
36156 - plugin_config conf;
36158 + plugin_config conf;
36161 INIT_FUNC(mod_redirect_init) {
36165 p = calloc(1, sizeof(*p));
36168 p->match_buf = buffer_init();
36169 p->location = buffer_init();
36175 FREE_FUNC(mod_redirect_free) {
36176 plugin_data *p = p_d;
36179 if (!p) return HANDLER_GO_ON;
36181 if (p->config_storage) {
36183 for (i = 0; i < srv->config_context->used; i++) {
36184 plugin_config *s = p->config_storage[i];
36187 pcre_keyvalue_buffer_free(s->redirect);
36192 free(p->config_storage);
36195 buffer_free(p->match_buf);
36196 buffer_free(p->location);
36202 return HANDLER_GO_ON;
36205 @@ -69,195 +69,137 @@
36206 plugin_data *p = p_d;
36210 - config_values_t cv[] = {
36212 + config_values_t cv[] = {
36213 { "url.redirect", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
36214 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36218 if (!p) return HANDLER_ERROR;
36222 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36225 for (i = 0; i < srv->config_context->used; i++) {
36229 data_array *da = (data_array *)du;
36232 s = calloc(1, sizeof(plugin_config));
36233 s->redirect = pcre_keyvalue_buffer_init();
36236 cv[0].destination = s->redirect;
36239 p->config_storage[i] = s;
36240 ca = ((data_config *)srv->config_context->data[i])->value;
36243 if (0 != config_insert_values_global(srv, ca, cv)) {
36244 return HANDLER_ERROR;
36248 if (NULL == (du = array_get_element(ca, "url.redirect"))) {
36249 /* no url.redirect defined */
36254 if (du->type != TYPE_ARRAY) {
36255 - log_error_write(srv, __FILE__, __LINE__, "sss",
36256 + log_error_write(srv, __FILE__, __LINE__, "sss",
36257 "unexpected type for key: ", "url.redirect", "array of strings");
36260 return HANDLER_ERROR;
36264 da = (data_array *)du;
36267 for (j = 0; j < da->value->used; j++) {
36268 if (da->value->data[j]->type != TYPE_STRING) {
36269 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
36270 - "unexpected type for key: ",
36272 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
36273 + "unexpected type for key: ",
36275 "[", da->value->data[j]->key, "](string)");
36278 return HANDLER_ERROR;
36281 - if (0 != pcre_keyvalue_buffer_append(s->redirect,
36283 + if (0 != pcre_keyvalue_buffer_append(s->redirect,
36284 ((data_string *)(da->value->data[j]))->key->ptr,
36285 ((data_string *)(da->value->data[j]))->value->ptr)) {
36287 - log_error_write(srv, __FILE__, __LINE__, "sb",
36289 + log_error_write(srv, __FILE__, __LINE__, "sb",
36290 "pcre-compile failed for", da->value->data[j]->key);
36296 return HANDLER_GO_ON;
36299 static int mod_redirect_patch_connection(server *srv, connection *con, plugin_data *p) {
36301 plugin_config *s = p->config_storage[0];
36304 p->conf.redirect = s->redirect;
36307 /* skip the first, the global context */
36308 for (i = 1; i < srv->config_context->used; i++) {
36309 data_config *dc = (data_config *)srv->config_context->data[i];
36310 s = p->config_storage[i];
36313 /* condition didn't match */
36314 if (!config_check_cond(srv, con, dc)) continue;
36318 for (j = 0; j < dc->value->used; j++) {
36319 data_unset *du = dc->value->data[j];
36322 if (0 == strcmp(du->key->ptr, "url.redirect")) {
36323 p->conf.redirect = s->redirect;
36324 p->conf.context = dc;
36333 static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_data) {
36335 plugin_data *p = p_data;
36344 * e.g. redirect /base/ to /index.php?section=base
36350 mod_redirect_patch_connection(srv, con, p);
36353 buffer_copy_string_buffer(p->match_buf, con->request.uri);
36355 - for (i = 0; i < p->conf.redirect->used; i++) {
36357 - pcre_extra *extra;
36358 - const char *pattern;
36359 - size_t pattern_len;
36361 - pcre_keyvalue *kv = p->conf.redirect->kv[i];
36366 - extra = kv->key_extra;
36367 - pattern = kv->value->ptr;
36368 - pattern_len = kv->value->used - 1;
36370 - if ((n = pcre_exec(match, extra, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
36371 - if (n != PCRE_ERROR_NOMATCH) {
36372 - log_error_write(srv, __FILE__, __LINE__, "sd",
36373 - "execution error while matching: ", n);
36374 - return HANDLER_ERROR;
36377 - const char **list;
36378 - size_t start, end;
36382 - pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
36384 - /* search for $[0-9] */
36386 - buffer_reset(p->location);
36388 - start = 0; end = pattern_len;
36389 - for (k = 0; k < pattern_len; k++) {
36390 - if ((pattern[k] == '$' || pattern[k] == '%') &&
36391 - isdigit((unsigned char)pattern[k + 1])) {
36394 - size_t num = pattern[k + 1] - '0';
36398 - buffer_append_string_len(p->location, pattern + start, end - start);
36400 - if (pattern[k] == '$') {
36401 - /* n is always > 0 */
36402 - if (num < (size_t)n) {
36403 - buffer_append_string(p->location, list[num]);
36406 - config_append_cond_match_buffer(con, p->conf.context, p->location, num);
36414 - buffer_append_string_len(p->location, pattern + start, pattern_len - start);
36418 - response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
36420 - con->http_status = 301;
36421 - con->file_finished = 1;
36423 - return HANDLER_FINISHED;
36425 + i = config_exec_pcre_keyvalue_buffer(con, p->conf.redirect, p->conf.context, p->match_buf, p->location);
36428 + response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
36430 + con->http_status = 301;
36431 + con->send->is_closed = 1;
36433 + return HANDLER_FINISHED;
36435 + else if (i != PCRE_ERROR_NOMATCH) {
36436 + log_error_write(srv, __FILE__, __LINE__, "s",
36437 + "execution error while matching", i);
36449 return HANDLER_GO_ON;
36452 @@ -265,13 +207,13 @@
36453 int mod_redirect_plugin_init(plugin *p) {
36454 p->version = LIGHTTPD_VERSION_ID;
36455 p->name = buffer_init_string("redirect");
36458 p->init = mod_redirect_init;
36459 p->handle_uri_clean = mod_redirect_uri_handler;
36460 p->set_defaults = mod_redirect_set_defaults;
36461 p->cleanup = mod_redirect_free;
36469 --- ../lighttpd-1.4.11/src/mod_rewrite.c 2005-09-29 20:59:10.000000000 +0300
36470 +++ lighttpd-1.5.0/src/mod_rewrite.c 2006-07-16 00:26:03.000000000 +0300
36475 -#ifdef HAVE_PCRE_H
36485 - rewrite_rule **ptr;
36489 -} rewrite_rule_buffer;
36492 - rewrite_rule_buffer *rewrite;
36493 + pcre_keyvalue_buffer *rewrite;
36495 data_config *context; /* to which apply me */
36498 @@ -42,20 +26,20 @@
36504 plugin_config **config_storage;
36506 - plugin_config conf;
36508 + plugin_config conf;
36511 static handler_ctx * handler_ctx_init() {
36512 handler_ctx * hctx;
36515 hctx = calloc(1, sizeof(*hctx));
36518 hctx->state = REWRITE_STATE_UNSET;
36525 @@ -63,207 +47,136 @@
36529 -rewrite_rule_buffer *rewrite_rule_buffer_init(void) {
36530 - rewrite_rule_buffer *kvb;
36532 - kvb = calloc(1, sizeof(*kvb));
36537 -int rewrite_rule_buffer_append(rewrite_rule_buffer *kvb, buffer *key, buffer *value, int once) {
36538 -#ifdef HAVE_PCRE_H
36540 - const char *errptr;
36543 - if (!key) return -1;
36545 - if (kvb->size == 0) {
36549 - kvb->ptr = malloc(kvb->size * sizeof(*kvb->ptr));
36551 - for(i = 0; i < kvb->size; i++) {
36552 - kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
36554 - } else if (kvb->used == kvb->size) {
36557 - kvb->ptr = realloc(kvb->ptr, kvb->size * sizeof(*kvb->ptr));
36559 - for(i = kvb->used; i < kvb->size; i++) {
36560 - kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
36564 - if (NULL == (kvb->ptr[kvb->used]->key = pcre_compile(key->ptr,
36565 - 0, &errptr, &erroff, NULL))) {
36570 - kvb->ptr[kvb->used]->value = buffer_init();
36571 - buffer_copy_string_buffer(kvb->ptr[kvb->used]->value, value);
36572 - kvb->ptr[kvb->used]->once = once;
36587 -void rewrite_rule_buffer_free(rewrite_rule_buffer *kvb) {
36588 -#ifdef HAVE_PCRE_H
36591 - for (i = 0; i < kvb->size; i++) {
36592 - if (kvb->ptr[i]->key) pcre_free(kvb->ptr[i]->key);
36593 - if (kvb->ptr[i]->value) buffer_free(kvb->ptr[i]->value);
36594 - free(kvb->ptr[i]);
36597 - if (kvb->ptr) free(kvb->ptr);
36604 INIT_FUNC(mod_rewrite_init) {
36608 p = calloc(1, sizeof(*p));
36611 p->match_buf = buffer_init();
36617 FREE_FUNC(mod_rewrite_free) {
36618 plugin_data *p = p_d;
36623 if (!p) return HANDLER_GO_ON;
36626 buffer_free(p->match_buf);
36627 if (p->config_storage) {
36629 for (i = 0; i < srv->config_context->used; i++) {
36630 plugin_config *s = p->config_storage[i];
36631 - rewrite_rule_buffer_free(s->rewrite);
36633 + pcre_keyvalue_buffer_free(s->rewrite);
36634 + buffer_free(s->once);
36638 free(p->config_storage);
36645 return HANDLER_GO_ON;
36648 static int parse_config_entry(server *srv, plugin_config *s, array *ca, const char *option, int once) {
36652 if (NULL != (du = array_get_element(ca, option))) {
36653 data_array *da = (data_array *)du;
36657 if (du->type != TYPE_ARRAY) {
36658 - log_error_write(srv, __FILE__, __LINE__, "sss",
36659 + log_error_write(srv, __FILE__, __LINE__, "sss",
36660 "unexpected type for key: ", option, "array of strings");
36663 return HANDLER_ERROR;
36667 da = (data_array *)du;
36670 for (j = 0; j < da->value->used; j++) {
36671 if (da->value->data[j]->type != TYPE_STRING) {
36672 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
36673 - "unexpected type for key: ",
36675 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
36676 + "unexpected type for key: ",
36678 "[", da->value->data[j]->key, "](string)");
36681 return HANDLER_ERROR;
36684 - if (0 != rewrite_rule_buffer_append(s->rewrite,
36685 - ((data_string *)(da->value->data[j]))->key,
36686 - ((data_string *)(da->value->data[j]))->value,
36689 + if (0 != pcre_keyvalue_buffer_append(s->rewrite,
36690 + ((data_string *)(da->value->data[j]))->key->ptr,
36691 + ((data_string *)(da->value->data[j]))->value->ptr)) {
36693 - log_error_write(srv, __FILE__, __LINE__, "sb",
36694 + log_error_write(srv, __FILE__, __LINE__, "sb",
36695 "pcre-compile failed for", da->value->data[j]->key);
36697 - log_error_write(srv, __FILE__, __LINE__, "s",
36698 + log_error_write(srv, __FILE__, __LINE__, "s",
36699 "pcre support is missing, please install libpcre and the headers");
36704 + buffer_append_string_len(s->once, CONST_STR_LEN("1"));
36706 + buffer_append_string_len(s->once, CONST_STR_LEN("0"));
36715 SETDEFAULTS_FUNC(mod_rewrite_set_defaults) {
36716 plugin_data *p = p_d;
36719 - config_values_t cv[] = {
36721 + config_values_t cv[] = {
36722 { "url.rewrite-repeat", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
36723 { "url.rewrite-once", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
36725 - /* old names, still supported
36728 + /* old names, still supported
36730 * url.rewrite remapped to url.rewrite-once
36731 * url.rewrite-final is url.rewrite-once
36735 { "url.rewrite", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
36736 { "url.rewrite-final", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
36737 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36741 if (!p) return HANDLER_ERROR;
36745 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36748 for (i = 0; i < srv->config_context->used; i++) {
36753 s = calloc(1, sizeof(plugin_config));
36754 - s->rewrite = rewrite_rule_buffer_init();
36756 - cv[0].destination = s->rewrite;
36757 - cv[1].destination = s->rewrite;
36758 - cv[2].destination = s->rewrite;
36760 + s->rewrite = pcre_keyvalue_buffer_init();
36761 + s->once = buffer_init();
36763 p->config_storage[i] = s;
36764 ca = ((data_config *)srv->config_context->data[i])->value;
36767 if (0 != config_insert_values_global(srv, ca, cv)) {
36768 return HANDLER_ERROR;
36772 parse_config_entry(srv, s, ca, "url.rewrite-once", 1);
36773 parse_config_entry(srv, s, ca, "url.rewrite-final", 1);
36774 parse_config_entry(srv, s, ca, "url.rewrite", 1);
36775 parse_config_entry(srv, s, ca, "url.rewrite-repeat", 0);
36779 return HANDLER_GO_ON;
36782 @@ -271,157 +184,107 @@
36784 plugin_config *s = p->config_storage[0];
36785 p->conf.rewrite = s->rewrite;
36787 + p->conf.once = s->once;
36789 /* skip the first, the global context */
36790 for (i = 1; i < srv->config_context->used; i++) {
36791 data_config *dc = (data_config *)srv->config_context->data[i];
36792 s = p->config_storage[i];
36795 if (COMP_HTTP_URL == dc->comp) continue;
36798 /* condition didn't match */
36799 if (!config_check_cond(srv, con, dc)) continue;
36803 for (j = 0; j < dc->value->used; j++) {
36804 data_unset *du = dc->value->data[j];
36807 if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite"))) {
36808 p->conf.rewrite = s->rewrite;
36809 + p->conf.once = s->once;
36810 p->conf.context = dc;
36811 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-once"))) {
36812 p->conf.rewrite = s->rewrite;
36813 + p->conf.once = s->once;
36814 p->conf.context = dc;
36815 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-repeat"))) {
36816 p->conf.rewrite = s->rewrite;
36817 + p->conf.once = s->once;
36818 p->conf.context = dc;
36819 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-final"))) {
36820 p->conf.rewrite = s->rewrite;
36821 + p->conf.once = s->once;
36822 p->conf.context = dc;
36831 URIHANDLER_FUNC(mod_rewrite_con_reset) {
36832 plugin_data *p = p_d;
36838 if (con->plugin_ctx[p->id]) {
36839 handler_ctx_free(con->plugin_ctx[p->id]);
36840 con->plugin_ctx[p->id] = NULL;
36844 return HANDLER_GO_ON;
36847 URIHANDLER_FUNC(mod_rewrite_uri_handler) {
36849 plugin_data *p = p_d;
36859 * e.g. rewrite /base/ to /index.php?section=base
36865 if (con->plugin_ctx[p->id]) {
36866 hctx = con->plugin_ctx[p->id];
36869 if (hctx->loops++ > 100) {
36870 - log_error_write(srv, __FILE__, __LINE__, "s",
36871 + log_error_write(srv, __FILE__, __LINE__, "s",
36872 "ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request, perhaps you want to use url.rewrite-once instead of url.rewrite-repeat");
36875 return HANDLER_ERROR;
36879 if (hctx->state == REWRITE_STATE_FINISHED) return HANDLER_GO_ON;
36883 mod_rewrite_patch_connection(srv, con, p);
36885 if (!p->conf.rewrite) return HANDLER_GO_ON;
36888 buffer_copy_string_buffer(p->match_buf, con->request.uri);
36890 - for (i = 0; i < p->conf.rewrite->used; i++) {
36892 - const char *pattern;
36893 - size_t pattern_len;
36895 - rewrite_rule *rule = p->conf.rewrite->ptr[i];
36899 - match = rule->key;
36900 - pattern = rule->value->ptr;
36901 - pattern_len = rule->value->used - 1;
36903 - if ((n = pcre_exec(match, NULL, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
36904 - if (n != PCRE_ERROR_NOMATCH) {
36905 - log_error_write(srv, __FILE__, __LINE__, "sd",
36906 - "execution error while matching: ", n);
36907 - return HANDLER_ERROR;
36910 - const char **list;
36911 - size_t start, end;
36915 - pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
36917 - /* search for $[0-9] */
36919 - buffer_reset(con->request.uri);
36921 - start = 0; end = pattern_len;
36922 - for (k = 0; k < pattern_len; k++) {
36923 - if ((pattern[k] == '$' || pattern[k] == '%') &&
36924 - isdigit((unsigned char)pattern[k + 1])) {
36927 - size_t num = pattern[k + 1] - '0';
36931 - buffer_append_string_len(con->request.uri, pattern + start, end - start);
36933 - if (pattern[k] == '$') {
36934 - /* n is always > 0 */
36935 - if (num < (size_t)n) {
36936 - buffer_append_string(con->request.uri, list[num]);
36939 - config_append_cond_match_buffer(con, p->conf.context, con->request.uri, num);
36947 - buffer_append_string_len(con->request.uri, pattern + start, pattern_len - start);
36951 - hctx = handler_ctx_init();
36953 - con->plugin_ctx[p->id] = hctx;
36955 - if (rule->once) hctx->state = REWRITE_STATE_FINISHED;
36957 - return HANDLER_COMEBACK;
36959 + i = config_exec_pcre_keyvalue_buffer(con, p->conf.rewrite, p->conf.context, p->match_buf, con->request.uri);
36962 + hctx = handler_ctx_init();
36964 + con->plugin_ctx[p->id] = hctx;
36966 + if (p->conf.once->ptr[i] == '1')
36967 + hctx->state = REWRITE_STATE_FINISHED;
36969 + return HANDLER_COMEBACK;
36971 + else if (i != PCRE_ERROR_NOMATCH) {
36972 + log_error_write(srv, __FILE__, __LINE__, "s",
36973 + "execution error while matching", i);
36981 @@ -434,17 +297,17 @@
36982 int mod_rewrite_plugin_init(plugin *p) {
36983 p->version = LIGHTTPD_VERSION_ID;
36984 p->name = buffer_init_string("rewrite");
36987 p->init = mod_rewrite_init;
36988 /* it has to stay _raw as we are matching on uri + querystring
36992 p->handle_uri_raw = mod_rewrite_uri_handler;
36993 p->set_defaults = mod_rewrite_set_defaults;
36994 p->cleanup = mod_rewrite_free;
36995 p->connection_reset = mod_rewrite_con_reset;
37003 --- ../lighttpd-1.4.11/src/mod_rrdtool.c 2005-08-22 01:52:24.000000000 +0300
37004 +++ lighttpd-1.5.0/src/mod_rrdtool.c 2006-09-07 00:57:05.000000000 +0300
37006 #include <stdlib.h>
37008 #include <string.h>
37009 -#include <unistd.h>
37013 @@ -20,10 +19,14 @@
37014 /* no need for waitpid if we don't have fork */
37015 #include <sys/wait.h>
37018 +#include "sys-files.h"
37019 +#include "sys-process.h"
37022 buffer *path_rrdtool_bin;
37026 double requests, *requests_ptr;
37027 double bytes_written, *bytes_written_ptr;
37028 double bytes_read, *bytes_read_ptr;
37029 @@ -31,84 +34,84 @@
37039 int read_fd, write_fd;
37043 int rrdtool_running;
37046 plugin_config **config_storage;
37047 plugin_config conf;
37050 INIT_FUNC(mod_rrd_init) {
37054 p = calloc(1, sizeof(*p));
37057 p->resp = buffer_init();
37058 p->cmd = buffer_init();
37064 FREE_FUNC(mod_rrd_free) {
37065 plugin_data *p = p_d;
37069 if (!p) return HANDLER_GO_ON;
37072 if (p->config_storage) {
37073 for (i = 0; i < srv->config_context->used; i++) {
37074 plugin_config *s = p->config_storage[i];
37077 buffer_free(s->path_rrdtool_bin);
37078 buffer_free(s->path_rrd);
37084 buffer_free(p->cmd);
37085 buffer_free(p->resp);
37088 free(p->config_storage);
37091 if (p->rrdtool_pid) {
37094 close(p->write_fd);
37097 /* collect status */
37098 waitpid(p->rrdtool_pid, &status, 0);
37106 return HANDLER_GO_ON;
37109 int mod_rrd_create_pipe(server *srv, plugin_data *p) {
37113 int to_rrdtool_fds[2];
37114 int from_rrdtool_fds[2];
37117 if (pipe(to_rrdtool_fds)) {
37118 - log_error_write(srv, __FILE__, __LINE__, "ss",
37119 + log_error_write(srv, __FILE__, __LINE__, "ss",
37120 "pipe failed: ", strerror(errno));
37125 if (pipe(from_rrdtool_fds)) {
37126 - log_error_write(srv, __FILE__, __LINE__, "ss",
37127 + log_error_write(srv, __FILE__, __LINE__, "ss",
37128 "pipe failed: ", strerror(errno));
37134 switch (pid = fork()) {
37136 @@ -117,33 +120,28 @@
37142 /* move stdout to from_rrdtool_fd[1] */
37143 close(STDOUT_FILENO);
37144 dup2(from_rrdtool_fds[1], STDOUT_FILENO);
37145 close(from_rrdtool_fds[1]);
37147 close(from_rrdtool_fds[0]);
37150 /* move the stdin to to_rrdtool_fd[0] */
37151 close(STDIN_FILENO);
37152 dup2(to_rrdtool_fds[0], STDIN_FILENO);
37153 close(to_rrdtool_fds[0]);
37155 close(to_rrdtool_fds[1]);
37158 close(STDERR_FILENO);
37160 - if (srv->errorlog_mode == ERRORLOG_FILE) {
37161 - dup2(srv->errorlog_fd, STDERR_FILENO);
37162 - close(srv->errorlog_fd);
37168 args = malloc(sizeof(*args) * argc);
37172 args[i++] = p->conf.path_rrdtool_bin->ptr;
37175 @@ -152,12 +150,12 @@
37176 for (i = 3; i < 256; i++) {
37182 execv(args[0], args);
37185 log_error_write(srv, __FILE__, __LINE__, "sss", "spawing rrdtool failed: ", strerror(errno), args[0]);
37191 @@ -168,19 +166,19 @@
37197 close(from_rrdtool_fds[1]);
37198 close(to_rrdtool_fds[0]);
37201 /* register PID and wait for them asyncronously */
37202 p->write_fd = to_rrdtool_fds[1];
37203 p->read_fd = from_rrdtool_fds[0];
37204 p->rrdtool_pid = pid;
37215 @@ -189,19 +187,19 @@
37217 static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) {
37221 /* check if DB already exists */
37222 if (0 == stat(s->path_rrd->ptr, &st)) {
37223 /* check if it is plain file */
37224 if (!S_ISREG(st.st_mode)) {
37225 - log_error_write(srv, __FILE__, __LINE__, "sb",
37226 + log_error_write(srv, __FILE__, __LINE__, "sb",
37227 "not a regular file:", s->path_rrd);
37228 return HANDLER_ERROR;
37232 /* create a new one */
37235 BUFFER_COPY_STRING_CONST(p->cmd, "create ");
37236 buffer_append_string_buffer(p->cmd, s->path_rrd);
37237 buffer_append_string(p->cmd, " --step 60 ");
37238 @@ -220,158 +218,155 @@
37239 buffer_append_string(p->cmd, "RRA:MIN:0.5:6:700 ");
37240 buffer_append_string(p->cmd, "RRA:MIN:0.5:24:775 ");
37241 buffer_append_string(p->cmd, "RRA:MIN:0.5:288:797\n");
37244 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
37245 - log_error_write(srv, __FILE__, __LINE__, "ss",
37246 + log_error_write(srv, __FILE__, __LINE__, "ss",
37247 "rrdtool-write: failed", strerror(errno));
37250 return HANDLER_ERROR;
37254 buffer_prepare_copy(p->resp, 4096);
37255 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
37256 - log_error_write(srv, __FILE__, __LINE__, "ss",
37257 + log_error_write(srv, __FILE__, __LINE__, "ss",
37258 "rrdtool-read: failed", strerror(errno));
37261 return HANDLER_ERROR;
37268 if (p->resp->ptr[0] != 'O' ||
37269 p->resp->ptr[1] != 'K') {
37270 - log_error_write(srv, __FILE__, __LINE__, "sbb",
37271 + log_error_write(srv, __FILE__, __LINE__, "sbb",
37272 "rrdtool-response:", p->cmd, p->resp);
37275 return HANDLER_ERROR;
37280 return HANDLER_GO_ON;
37283 -#define PATCH(x) \
37284 - p->conf.x = s->x;
37285 static int mod_rrd_patch_connection(server *srv, connection *con, plugin_data *p) {
37287 plugin_config *s = p->config_storage[0];
37289 - PATCH(path_rrdtool_bin);
37293 + PATCH_OPTION(path_rrdtool_bin);
37294 + PATCH_OPTION(path_rrd);
37296 p->conf.bytes_written_ptr = &(s->bytes_written);
37297 p->conf.bytes_read_ptr = &(s->bytes_read);
37298 p->conf.requests_ptr = &(s->requests);
37301 /* skip the first, the global context */
37302 for (i = 1; i < srv->config_context->used; i++) {
37303 data_config *dc = (data_config *)srv->config_context->data[i];
37304 s = p->config_storage[i];
37307 /* condition didn't match */
37308 if (!config_check_cond(srv, con, dc)) continue;
37312 for (j = 0; j < dc->value->used; j++) {
37313 data_unset *du = dc->value->data[j];
37316 if (buffer_is_equal_string(du->key, CONST_STR_LEN("rrdtool.db-name"))) {
37318 + PATCH_OPTION(path_rrd);
37319 /* get pointers to double values */
37322 p->conf.bytes_written_ptr = &(s->bytes_written);
37323 p->conf.bytes_read_ptr = &(s->bytes_read);
37324 p->conf.requests_ptr = &(s->requests);
37334 SETDEFAULTS_FUNC(mod_rrd_set_defaults) {
37335 plugin_data *p = p_d;
37338 - config_values_t cv[] = {
37340 + config_values_t cv[] = {
37341 { "rrdtool.binary", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
37342 { "rrdtool.db-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
37343 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37347 if (!p) return HANDLER_ERROR;
37350 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37353 for (i = 0; i < srv->config_context->used; i++) {
37357 s = calloc(1, sizeof(plugin_config));
37358 s->path_rrdtool_bin = buffer_init();
37359 s->path_rrd = buffer_init();
37361 s->bytes_written = 0;
37365 cv[0].destination = s->path_rrdtool_bin;
37366 cv[1].destination = s->path_rrd;
37369 p->config_storage[i] = s;
37372 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37373 return HANDLER_ERROR;
37377 if (i > 0 && !buffer_is_empty(s->path_rrdtool_bin)) {
37378 /* path_rrdtool_bin is a global option */
37380 - log_error_write(srv, __FILE__, __LINE__, "s",
37382 + log_error_write(srv, __FILE__, __LINE__, "s",
37383 "rrdtool.binary can only be set as a global option.");
37386 return HANDLER_ERROR;
37393 p->conf.path_rrdtool_bin = p->config_storage[0]->path_rrdtool_bin;
37394 p->rrdtool_running = 0;
37397 /* check for dir */
37400 if (buffer_is_empty(p->conf.path_rrdtool_bin)) {
37401 - log_error_write(srv, __FILE__, __LINE__, "s",
37402 + log_error_write(srv, __FILE__, __LINE__, "s",
37403 "rrdtool.binary has to be set");
37404 return HANDLER_ERROR;
37408 /* open the pipe to rrdtool */
37409 if (mod_rrd_create_pipe(srv, p)) {
37410 return HANDLER_ERROR;
37414 p->rrdtool_running = 1;
37417 return HANDLER_GO_ON;
37420 TRIGGER_FUNC(mod_rrd_trigger) {
37421 plugin_data *p = p_d;
37425 if (!p->rrdtool_running) return HANDLER_GO_ON;
37426 if ((srv->cur_ts % 60) != 0) return HANDLER_GO_ON;
37429 for (i = 0; i < srv->config_context->used; i++) {
37430 plugin_config *s = p->config_storage[i];
37434 if (buffer_is_empty(s->path_rrd)) continue;
37437 /* write the data down every minute */
37440 if (HANDLER_GO_ON != mod_rrdtool_create_rrd(srv, p, s)) return HANDLER_ERROR;
37443 BUFFER_COPY_STRING_CONST(p->cmd, "update ");
37444 buffer_append_string_buffer(p->cmd, s->path_rrd);
37445 BUFFER_APPEND_STRING_CONST(p->cmd, " N:");
37446 @@ -381,69 +376,69 @@
37447 BUFFER_APPEND_STRING_CONST(p->cmd, ":");
37448 buffer_append_long(p->cmd, s->requests);
37449 BUFFER_APPEND_STRING_CONST(p->cmd, "\n");
37452 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
37453 p->rrdtool_running = 0;
37455 - log_error_write(srv, __FILE__, __LINE__, "ss",
37457 + log_error_write(srv, __FILE__, __LINE__, "ss",
37458 "rrdtool-write: failed", strerror(errno));
37461 return HANDLER_ERROR;
37465 buffer_prepare_copy(p->resp, 4096);
37466 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
37467 p->rrdtool_running = 0;
37469 - log_error_write(srv, __FILE__, __LINE__, "ss",
37471 + log_error_write(srv, __FILE__, __LINE__, "ss",
37472 "rrdtool-read: failed", strerror(errno));
37475 return HANDLER_ERROR;
37482 if (p->resp->ptr[0] != 'O' ||
37483 p->resp->ptr[1] != 'K') {
37484 p->rrdtool_running = 0;
37486 - log_error_write(srv, __FILE__, __LINE__, "sbb",
37488 + log_error_write(srv, __FILE__, __LINE__, "sbb",
37489 "rrdtool-response:", p->cmd, p->resp);
37492 return HANDLER_ERROR;
37495 s->bytes_written = 0;
37500 return HANDLER_GO_ON;
37503 REQUESTDONE_FUNC(mod_rrd_account) {
37504 plugin_data *p = p_d;
37507 mod_rrd_patch_connection(srv, con, p);
37510 *(p->conf.requests_ptr) += 1;
37511 *(p->conf.bytes_written_ptr) += con->bytes_written;
37512 *(p->conf.bytes_read_ptr) += con->bytes_read;
37515 return HANDLER_GO_ON;
37518 int mod_rrdtool_plugin_init(plugin *p) {
37519 p->version = LIGHTTPD_VERSION_ID;
37520 p->name = buffer_init_string("rrd");
37523 p->init = mod_rrd_init;
37524 p->cleanup = mod_rrd_free;
37525 p->set_defaults= mod_rrd_set_defaults;
37528 p->handle_trigger = mod_rrd_trigger;
37529 - p->handle_request_done = mod_rrd_account;
37531 + p->handle_response_done = mod_rrd_account;
37538 --- ../lighttpd-1.4.11/src/mod_scgi.c 2006-03-04 17:15:26.000000000 +0200
37539 +++ lighttpd-1.5.0/src/mod_scgi.c 2006-09-07 00:57:05.000000000 +0300
37541 #include <sys/types.h>
37542 -#include <unistd.h>
37545 #include <string.h>
37546 @@ -13,11 +12,11 @@
37547 #include "keyvalue.h"
37550 -#include "http_chunk.h"
37551 #include "fdevent.h"
37552 #include "connections.h"
37553 #include "response.h"
37554 #include "joblist.h"
37555 +#include "http_resp.h"
37557 #include "plugin.h"
37562 #include "sys-socket.h"
37564 +#include "sys-files.h"
37565 +#include "sys-strings.h"
37566 +#include "sys-process.h"
37568 #ifndef UNIX_PATH_MAX
37569 # define UNIX_PATH_MAX 108
37570 @@ -46,30 +47,29 @@
37571 enum {EOL_UNSET, EOL_N, EOL_RN};
37579 * - add timeout for a connect to a non-scgi process
37580 * (use state_timestamp + state)
37585 typedef struct scgi_proc {
37586 size_t id; /* id will be between 1 and max_procs */
37587 buffer *socket; /* config.socket + "-" + id */
37588 unsigned port; /* config.port + pno */
37590 - pid_t pid; /* PID of the spawned process (0 if not spawned locally) */
37592 + pid_t pid; /* PID of the spawned process (0 if not spawned locally) */
37594 size_t load; /* number of requests waiting on this process */
37596 time_t last_used; /* see idle_timeout */
37597 size_t requests; /* see max_requests */
37598 struct scgi_proc *prev, *next; /* see first */
37601 time_t disable_ts; /* replace by host->something */
37606 enum { PROC_STATE_UNSET, /* init-phase */
37608 PROC_STATE_KILLED, /* was killed as we don't have the load anymore */
37609 PROC_STATE_DIED, /* marked as dead, should be restarted */
37610 PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
37616 @@ -86,20 +86,20 @@
37617 * sorted by lowest load
37619 * whenever a job is done move it up in the list
37620 - * until it is sorted, move it down as soon as the
37621 + * until it is sorted, move it down as soon as the
37624 - scgi_proc *first;
37625 - scgi_proc *unused_procs;
37626 + scgi_proc *first;
37627 + scgi_proc *unused_procs;
37631 * spawn at least min_procs, at max_procs.
37633 - * as soon as the load of the first entry
37634 + * as soon as the load of the first entry
37635 * is max_load_per_proc we spawn a new one
37636 - * and add it to the first entry and give it
37637 + * and add it to the first entry and give it
37643 unsigned short min_procs;
37644 @@ -111,44 +111,44 @@
37647 * kick the process from the list if it was not
37648 - * used for idle_timeout until min_procs is
37649 + * used for idle_timeout until min_procs is
37650 * reached. this helps to get the processlist
37651 * small again we had a small peak load.
37656 unsigned short idle_timeout;
37660 * time after a disabled remote connection is tried to be re-enabled
37668 unsigned short disable_time;
37671 * same scgi processes get a little bit larger
37672 - * than wanted. max_requests_per_proc kills a
37673 + * than wanted. max_requests_per_proc kills a
37674 * process after a number of handled requests.
37677 size_t max_requests_per_proc;
37688 - * if host is one of the local IP adresses the
37689 + * if host is one of the local IP adresses the
37690 * whole connection is local
37692 * if tcp/ip should be used host AND port have
37693 - * to be specified
37697 + * to be specified
37701 unsigned short port;
37704 @@ -161,7 +161,7 @@
37706 buffer *unixsocket;
37708 - /* if socket is local we can start the scgi
37709 + /* if socket is local we can start the scgi
37712 * bin-path is the path to the binary
37713 @@ -169,19 +169,19 @@
37714 * check min_procs and max_procs for the number
37715 * of process to start-up
37717 - buffer *bin_path;
37719 - /* bin-path is set bin-environment is taken to
37720 + buffer *bin_path;
37722 + /* bin-path is set bin-environment is taken to
37723 * create the environement before starting the
37731 array *bin_env_copy;
37735 - * docroot-translation between URL->phys and the
37736 + * docroot-translation between URL->phys and the
37740 @@ -192,7 +192,7 @@
37744 - * check_local tell you if the phys file is stat()ed
37745 + * check_local tell you if the phys file is stat()ed
37746 * or not. FastCGI doesn't care if the service is
37747 * remote. If the web-server side doesn't contain
37748 * the scgi-files we should not stat() for them
37749 @@ -202,33 +202,33 @@
37752 * append PATH_INFO to SCRIPT_FILENAME
37755 * php needs this if cgi.fix_pathinfo is provied
37761 ssize_t load; /* replace by host->load */
37763 size_t max_id; /* corresponds most of the time to
37767 only if a process is killed max_id waits for the process itself
37768 to die and decrements its afterwards */
37769 } scgi_extension_host;
37772 * one extension can have multiple hosts assigned
37773 - * one host can spawn additional processes on the same
37774 + * one host can spawn additional processes on the same
37775 * socket (if we control it)
37777 * ext -> host -> procs
37780 - * if the scgi process is remote that whole goes down
37781 + * if the scgi process is remote that whole goes down
37784 * ext -> host -> procs
37788 * in case of PHP and FCGI_CHILDREN we have again a procs
37789 * but we don't control it directly.
37790 @@ -239,7 +239,7 @@
37791 buffer *key; /* like .php */
37793 scgi_extension_host **hosts;
37799 @@ -253,14 +253,14 @@
37817 @@ -268,52 +268,51 @@
37818 /* generic plugin data, shared between all connections */
37827 - buffer *parse_response;
37832 plugin_config **config_storage;
37835 plugin_config conf; /* this is only used as long as no handler_ctx is setup */
37838 /* connection specific data */
37839 -typedef enum { FCGI_STATE_INIT, FCGI_STATE_CONNECT, FCGI_STATE_PREPARE_WRITE,
37840 - FCGI_STATE_WRITE, FCGI_STATE_READ
37843 + SCGI_STATE_CONNECT,
37844 + SCGI_STATE_PREPARE_WRITE,
37845 + SCGI_STATE_WRITE,
37846 + SCGI_STATE_RESPONSE_HEADER,
37847 + SCGI_STATE_RESPONSE_CONTENT,
37849 } scgi_connection_state_t;
37852 - buffer *response;
37853 - size_t response_len;
37854 - int response_type;
37855 - int response_padding;
37858 scgi_extension_host *host;
37861 scgi_connection_state_t state;
37862 time_t state_timestamp;
37865 int reconnects; /* number of reconnect attempts */
37872 - buffer *response_header;
37875 int delayed; /* flag to mark that the connect() is delayed */
37879 - int fd; /* fd to the scgi process */
37880 - int fde_ndx; /* index into the fd-event buffer */
37881 + iosocket *sock; /* fd to the scgi process */
37887 plugin_config conf;
37890 connection *remote_conn; /* dumb pointer */
37891 plugin_data *plugin_data; /* dumb pointer */
37893 @@ -328,42 +327,30 @@
37895 static handler_ctx * handler_ctx_init() {
37896 handler_ctx * hctx;
37899 hctx = calloc(1, sizeof(*hctx));
37902 - hctx->fde_ndx = -1;
37904 - hctx->response = buffer_init();
37905 - hctx->response_header = buffer_init();
37908 + hctx->sock = iosocket_init();;
37910 hctx->request_id = 0;
37911 - hctx->state = FCGI_STATE_INIT;
37912 + hctx->state = SCGI_STATE_INIT;
37915 - hctx->response_len = 0;
37916 - hctx->response_type = 0;
37917 - hctx->response_padding = 0;
37921 hctx->reconnects = 0;
37923 hctx->wb = chunkqueue_init();
37925 + hctx->rb = chunkqueue_init();
37930 static void handler_ctx_free(handler_ctx *hctx) {
37931 - buffer_free(hctx->response);
37932 - buffer_free(hctx->response_header);
37934 chunkqueue_free(hctx->wb);
37937 - if (hctx->rb->ptr) free(hctx->rb->ptr);
37941 + chunkqueue_free(hctx->rb);
37943 + iosocket_free(hctx->sock);
37948 @@ -372,20 +359,20 @@
37950 f = calloc(1, sizeof(*f));
37951 f->socket = buffer_init();
37961 void scgi_process_free(scgi_proc *f) {
37965 scgi_process_free(f->next);
37968 buffer_free(f->socket);
37974 @@ -400,62 +387,62 @@
37975 f->bin_path = buffer_init();
37976 f->bin_env = array_init();
37977 f->bin_env_copy = array_init();
37983 void scgi_host_free(scgi_extension_host *h) {
37987 buffer_free(h->host);
37988 buffer_free(h->unixsocket);
37989 buffer_free(h->docroot);
37990 buffer_free(h->bin_path);
37991 array_free(h->bin_env);
37992 array_free(h->bin_env_copy);
37995 scgi_process_free(h->first);
37996 scgi_process_free(h->unused_procs);
38004 scgi_exts *scgi_extensions_init() {
38007 f = calloc(1, sizeof(*f));
38013 void scgi_extensions_free(scgi_exts *f) {
38020 for (i = 0; i < f->used; i++) {
38021 scgi_extension *fe;
38028 for (j = 0; j < fe->used; j++) {
38029 scgi_extension_host *h;
38039 buffer_free(fe->key);
38053 @@ -504,99 +491,103 @@
38057 - fe->hosts[fe->used++] = fh;
38058 + fe->hosts[fe->used++] = fh;
38065 INIT_FUNC(mod_scgi_init) {
38069 p = calloc(1, sizeof(*p));
38072 p->scgi_env = buffer_init();
38075 p->path = buffer_init();
38076 - p->parse_response = buffer_init();
38078 + p->resp = http_response_init();
38084 FREE_FUNC(mod_scgi_free) {
38085 plugin_data *p = p_d;
38090 buffer_free(p->scgi_env);
38091 buffer_free(p->path);
38092 - buffer_free(p->parse_response);
38094 + http_response_free(p->resp);
38096 if (p->config_storage) {
38098 for (i = 0; i < srv->config_context->used; i++) {
38099 plugin_config *s = p->config_storage[i];
38108 for (j = 0; j < exts->used; j++) {
38109 scgi_extension *ex;
38112 ex = exts->exts[j];
38115 for (n = 0; n < ex->used; n++) {
38117 scgi_extension_host *host;
38120 host = ex->hosts[n];
38123 for (proc = host->first; proc; proc = proc->next) {
38125 if (proc->pid != 0) kill(proc->pid, SIGTERM);
38127 - if (proc->is_local &&
38130 + if (proc->is_local &&
38131 !buffer_is_empty(proc->socket)) {
38132 unlink(proc->socket->ptr);
38137 for (proc = host->unused_procs; proc; proc = proc->next) {
38139 if (proc->pid != 0) kill(proc->pid, SIGTERM);
38141 - if (proc->is_local &&
38144 + if (proc->is_local &&
38145 !buffer_is_empty(proc->socket)) {
38146 unlink(proc->socket->ptr);
38153 scgi_extensions_free(s->exts);
38158 free(p->config_storage);
38165 return HANDLER_GO_ON;
38168 static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
38172 if (!key || !val) return -1;
38175 dst = malloc(key_len + val_len + 3);
38176 memcpy(dst, key, key_len);
38177 dst[key_len] = '=';
38178 /* add the \0 from the value */
38179 memcpy(dst + key_len + 1, val, val_len + 1);
38182 if (env->size == 0) {
38184 env->ptr = malloc(env->size * sizeof(*env->ptr));
38185 @@ -604,13 +595,13 @@
38187 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
38191 env->ptr[env->used++] = dst;
38197 -static int scgi_spawn_connection(server *srv,
38198 +static int scgi_spawn_connection(server *srv,
38200 scgi_extension_host *host,
38202 @@ -622,31 +613,27 @@
38204 struct sockaddr_in scgi_addr_in;
38205 struct sockaddr *scgi_addr;
38216 if (p->conf.debug) {
38217 log_error_write(srv, __FILE__, __LINE__, "sdb",
38218 "new proc, socket:", proc->port, proc->socket);
38222 if (!buffer_is_empty(proc->socket)) {
38223 memset(&scgi_addr, 0, sizeof(scgi_addr));
38226 #ifdef HAVE_SYS_UN_H
38227 scgi_addr_un.sun_family = AF_UNIX;
38228 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
38232 servlen = SUN_LEN(&scgi_addr_un);
38234 - /* stevens says: */
38235 - servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
38238 socket_type = AF_UNIX;
38239 scgi_addr = (struct sockaddr *) &scgi_addr_un;
38241 @@ -656,115 +643,115 @@
38244 scgi_addr_in.sin_family = AF_INET;
38247 if (buffer_is_empty(host->host)) {
38248 scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
38250 struct hostent *he;
38253 /* set a usefull default */
38254 scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
38259 if (NULL == (he = gethostbyname(host->host->ptr))) {
38260 - log_error_write(srv, __FILE__, __LINE__,
38261 - "sdb", "gethostbyname failed: ",
38262 + log_error_write(srv, __FILE__, __LINE__,
38263 + "sdb", "gethostbyname failed: ",
38264 h_errno, host->host);
38269 if (he->h_addrtype != AF_INET) {
38270 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
38275 if (he->h_length != sizeof(struct in_addr)) {
38276 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
38281 memcpy(&(scgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
38285 scgi_addr_in.sin_port = htons(proc->port);
38286 servlen = sizeof(scgi_addr_in);
38289 socket_type = AF_INET;
38290 scgi_addr = (struct sockaddr *) &scgi_addr_in;
38294 if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
38295 - log_error_write(srv, __FILE__, __LINE__, "ss",
38296 + log_error_write(srv, __FILE__, __LINE__, "ss",
38297 "failed:", strerror(errno));
38302 if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
38303 /* server is not up, spawn in */
38308 if (!buffer_is_empty(proc->socket)) {
38309 unlink(proc->socket->ptr);
38316 /* reopen socket */
38317 if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
38318 - log_error_write(srv, __FILE__, __LINE__, "ss",
38319 + log_error_write(srv, __FILE__, __LINE__, "ss",
38320 "socket failed:", strerror(errno));
38326 if (setsockopt(scgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
38327 - log_error_write(srv, __FILE__, __LINE__, "ss",
38328 + log_error_write(srv, __FILE__, __LINE__, "ss",
38329 "socketsockopt failed:", strerror(errno));
38334 /* create socket */
38335 if (-1 == bind(scgi_fd, scgi_addr, servlen)) {
38336 - log_error_write(srv, __FILE__, __LINE__, "sbds",
38337 - "bind failed for:",
38340 + log_error_write(srv, __FILE__, __LINE__, "sbds",
38341 + "bind failed for:",
38349 if (-1 == listen(scgi_fd, 1024)) {
38350 - log_error_write(srv, __FILE__, __LINE__, "ss",
38351 + log_error_write(srv, __FILE__, __LINE__, "ss",
38352 "listen failed:", strerror(errno));
38359 switch ((child = fork())) {
38369 /* create environment */
38375 /* we don't need the client socket */
38376 for (fd = 3; fd < 256; fd++) {
38377 if (fd != 2 && fd != scgi_fd) close(fd);
38381 /* build clean environment */
38382 if (host->bin_env_copy->used) {
38383 for (i = 0; i < host->bin_env_copy->used; i++) {
38384 data_string *ds = (data_string *)host->bin_env_copy->data[i];
38388 if (NULL != (ge = getenv(ds->value->ptr))) {
38389 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
38391 @@ -772,44 +759,44 @@
38393 for (i = 0; environ[i]; i++) {
38397 if (NULL != (eq = strchr(environ[i], '='))) {
38398 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
38404 /* create environment */
38405 for (i = 0; i < host->bin_env->used; i++) {
38406 data_string *ds = (data_string *)host->bin_env->data[i];
38409 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
38413 for (i = 0; i < env.used; i++) {
38414 /* search for PHP_FCGI_CHILDREN */
38415 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
38419 /* not found, add a default */
38420 if (i == env.used) {
38421 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
38425 env.ptr[env.used] = NULL;
38429 buffer_copy_string(b, "exec ");
38430 buffer_append_string_buffer(b, host->bin_path);
38434 execle("/bin/sh", "sh", "-c", b->ptr, NULL, env.ptr);
38436 - log_error_write(srv, __FILE__, __LINE__, "sbs",
38438 + log_error_write(srv, __FILE__, __LINE__, "sbs",
38439 "execl failed for:", host->bin_path, strerror(errno));
38448 @@ -817,32 +804,32 @@
38455 select(0, NULL, NULL, NULL, &tv);
38458 switch (waitpid(child, &status, WNOHANG)) {
38460 /* child still running after timeout, good */
38463 /* no PID found ? should never happen */
38464 - log_error_write(srv, __FILE__, __LINE__, "ss",
38465 + log_error_write(srv, __FILE__, __LINE__, "ss",
38466 "pid not found:", strerror(errno));
38469 /* the child should not terminate at all */
38470 if (WIFEXITED(status)) {
38471 - log_error_write(srv, __FILE__, __LINE__, "sd",
38472 - "child exited (is this a SCGI binary ?):",
38473 + log_error_write(srv, __FILE__, __LINE__, "sd",
38474 + "child exited (is this a SCGI binary ?):",
38475 WEXITSTATUS(status));
38476 } else if (WIFSIGNALED(status)) {
38477 - log_error_write(srv, __FILE__, __LINE__, "sd",
38478 - "child signaled:",
38479 + log_error_write(srv, __FILE__, __LINE__, "sd",
38480 + "child signaled:",
38483 - log_error_write(srv, __FILE__, __LINE__, "sd",
38484 - "child died somehow:",
38485 + log_error_write(srv, __FILE__, __LINE__, "sd",
38486 + "child died somehow:",
38490 @@ -852,26 +839,26 @@
38492 proc->last_used = srv->cur_ts;
38493 proc->is_local = 1;
38500 proc->is_local = 0;
38504 if (p->conf.debug) {
38505 log_error_write(srv, __FILE__, __LINE__, "sb",
38506 "(debug) socket is already used, won't spawn:",
38512 proc->state = PROC_STATE_RUNNING;
38513 host->active_procs++;
38522 @@ -880,89 +867,89 @@
38523 plugin_data *p = p_d;
38527 - config_values_t cv[] = {
38529 + config_values_t cv[] = {
38530 { "scgi.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
38531 { "scgi.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
38532 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
38536 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
38539 for (i = 0; i < srv->config_context->used; i++) {
38544 s = malloc(sizeof(plugin_config));
38545 s->exts = scgi_extensions_init();
38549 cv[0].destination = s->exts;
38550 cv[1].destination = &(s->debug);
38553 p->config_storage[i] = s;
38554 ca = ((data_config *)srv->config_context->data[i])->value;
38557 if (0 != config_insert_values_global(srv, ca, cv)) {
38558 return HANDLER_ERROR;
38568 if (NULL != (du = array_get_element(ca, "scgi.server"))) {
38570 data_array *da = (data_array *)du;
38573 if (du->type != TYPE_ARRAY) {
38574 - log_error_write(srv, __FILE__, __LINE__, "sss",
38575 + log_error_write(srv, __FILE__, __LINE__, "sss",
38576 "unexpected type for key: ", "scgi.server", "array of strings");
38579 return HANDLER_ERROR;
38584 - * scgi.server = ( "<ext>" => ( ... ),
38588 + * scgi.server = ( "<ext>" => ( ... ),
38589 * "<ext>" => ( ... ) )
38593 for (j = 0; j < da->value->used; j++) {
38595 data_array *da_ext = (data_array *)da->value->data[j];
38598 if (da->value->data[j]->type != TYPE_ARRAY) {
38599 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
38600 - "unexpected type for key: ", "scgi.server",
38601 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
38602 + "unexpected type for key: ", "scgi.server",
38603 "[", da->value->data[j]->key, "](string)");
38606 return HANDLER_ERROR;
38610 - * da_ext->key == name of the extension
38613 + * da_ext->key == name of the extension
38617 - * scgi.server = ( "<ext>" =>
38618 - * ( "<host>" => ( ... ),
38621 + * scgi.server = ( "<ext>" =>
38622 + * ( "<host>" => ( ... ),
38623 * "<host>" => ( ... )
38630 for (n = 0; n < da_ext->value->used; n++) {
38631 data_array *da_host = (data_array *)da_ext->value->data[n];
38634 scgi_extension_host *df;
38636 - config_values_t fcv[] = {
38638 + config_values_t fcv[] = {
38639 { "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
38640 { "docroot", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
38641 { "socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
38642 { "bin-path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
38645 { "check-local", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
38646 { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
38647 { "min-procs-not-working", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 this is broken for now */
38648 @@ -970,37 +957,37 @@
38649 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
38650 { "idle-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
38651 { "disable-time", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
38654 { "bin-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
38655 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
38660 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
38664 if (da_host->type != TYPE_ARRAY) {
38665 - log_error_write(srv, __FILE__, __LINE__, "ssSBS",
38666 - "unexpected type for key:",
38668 + log_error_write(srv, __FILE__, __LINE__, "ssSBS",
38669 + "unexpected type for key:",
38671 "[", da_host->key, "](string)");
38674 return HANDLER_ERROR;
38678 df = scgi_host_init();
38681 df->check_local = 1;
38684 df->max_load_per_proc = 1;
38685 df->idle_timeout = 60;
38686 df->disable_time = 60;
38689 fcv[0].destination = df->host;
38690 fcv[1].destination = df->docroot;
38691 fcv[2].destination = df->unixsocket;
38692 fcv[3].destination = df->bin_path;
38695 fcv[4].destination = &(df->check_local);
38696 fcv[5].destination = &(df->port);
38697 fcv[6].destination = &(df->min_procs);
38698 @@ -1008,47 +995,47 @@
38699 fcv[8].destination = &(df->max_load_per_proc);
38700 fcv[9].destination = &(df->idle_timeout);
38701 fcv[10].destination = &(df->disable_time);
38704 fcv[11].destination = df->bin_env;
38705 fcv[12].destination = df->bin_env_copy;
38710 if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
38711 return HANDLER_ERROR;
38714 - if ((!buffer_is_empty(df->host) || df->port) &&
38716 + if ((!buffer_is_empty(df->host) || df->port) &&
38717 !buffer_is_empty(df->unixsocket)) {
38718 - log_error_write(srv, __FILE__, __LINE__, "s",
38719 + log_error_write(srv, __FILE__, __LINE__, "s",
38720 "either host+port or socket");
38723 return HANDLER_ERROR;
38727 if (!buffer_is_empty(df->unixsocket)) {
38728 /* unix domain socket */
38731 if (df->unixsocket->used > UNIX_PATH_MAX - 2) {
38732 - log_error_write(srv, __FILE__, __LINE__, "s",
38733 + log_error_write(srv, __FILE__, __LINE__, "s",
38734 "path of the unixdomain socket is too large");
38735 return HANDLER_ERROR;
38740 - if (buffer_is_empty(df->host) &&
38742 + if (buffer_is_empty(df->host) &&
38743 buffer_is_empty(df->bin_path)) {
38744 - log_error_write(srv, __FILE__, __LINE__, "sbbbs",
38745 - "missing key (string):",
38746 + log_error_write(srv, __FILE__, __LINE__, "sbbbs",
38747 + "missing key (string):",
38754 return HANDLER_ERROR;
38755 } else if (df->port == 0) {
38756 - log_error_write(srv, __FILE__, __LINE__, "sbbbs",
38757 - "missing key (short):",
38758 + log_error_write(srv, __FILE__, __LINE__, "sbbbs",
38759 + "missing key (short):",
38763 @@ -1056,14 +1043,14 @@
38764 return HANDLER_ERROR;
38768 - if (!buffer_is_empty(df->bin_path)) {
38770 + if (!buffer_is_empty(df->bin_path)) {
38771 /* a local socket + self spawning */
38775 if (df->min_procs > df->max_procs) df->max_procs = df->min_procs;
38776 if (df->max_load_per_proc < 1) df->max_load_per_proc = 0;
38780 log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
38781 "--- scgi spawning local",
38782 @@ -1073,7 +1060,7 @@
38783 "\n\tmin-procs:", df->min_procs,
38784 "\n\tmax-procs:", df->max_procs);
38788 for (pno = 0; pno < df->min_procs; pno++) {
38791 @@ -1088,7 +1075,7 @@
38792 buffer_append_string(proc->socket, "-");
38793 buffer_append_long(proc->socket, pno);
38798 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
38799 "--- scgi spawning",
38800 @@ -1096,53 +1083,53 @@
38801 "\n\tsocket", df->unixsocket,
38802 "\n\tcurrent:", pno, "/", df->min_procs);
38806 if (scgi_spawn_connection(srv, p, df, proc)) {
38807 log_error_write(srv, __FILE__, __LINE__, "s",
38808 "[ERROR]: spawning fcgi failed.");
38809 return HANDLER_ERROR;
38813 proc->next = df->first;
38814 if (df->first) df->first->prev = proc;
38823 fp = scgi_process_init();
38824 fp->id = df->num_procs++;
38826 df->active_procs++;
38827 fp->state = PROC_STATE_RUNNING;
38830 if (buffer_is_empty(df->unixsocket)) {
38831 fp->port = df->port;
38833 buffer_copy_string_buffer(fp->socket, df->unixsocket);
38845 /* if extension already exists, take it */
38846 scgi_extension_insert(s->exts, da_ext->key, df);
38853 return HANDLER_GO_ON;
38856 static int scgi_set_state(server *srv, handler_ctx *hctx, scgi_connection_state_t state) {
38857 hctx->state = state;
38858 hctx->state_timestamp = srv->cur_ts;
38864 @@ -1150,35 +1137,35 @@
38865 void scgi_connection_cleanup(server *srv, handler_ctx *hctx) {
38870 if (NULL == hctx) return;
38873 p = hctx->plugin_data;
38874 con = hctx->remote_conn;
38877 if (con->mode != p->id) {
38882 - if (hctx->fd != -1) {
38883 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
38884 - fdevent_unregister(srv->ev, hctx->fd);
38887 + if (hctx->sock->fd != -1) {
38888 + fdevent_event_del(srv->ev, hctx->sock);
38889 + fdevent_unregister(srv->ev, hctx->sock);
38890 + closesocket(hctx->sock->fd);
38891 + hctx->sock->fd = -1;
38896 if (hctx->host && hctx->proc) {
38897 hctx->host->load--;
38900 if (hctx->got_proc) {
38901 /* after the connect the process gets a load */
38902 hctx->proc->load--;
38905 if (p->conf.debug) {
38906 log_error_write(srv, __FILE__, __LINE__, "sddb",
38911 hctx->proc->pid, hctx->proc->socket);
38914 @@ -1186,87 +1173,87 @@
38915 scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
38920 handler_ctx_free(hctx);
38921 - con->plugin_ctx[p->id] = NULL;
38922 + con->plugin_ctx[p->id] = NULL;
38925 static int scgi_reconnect(server *srv, handler_ctx *hctx) {
38926 plugin_data *p = hctx->plugin_data;
38937 * connect was ok, connection was accepted
38938 * but the php accept loop checks after the accept if it should die or not.
38940 - * if yes we can only detect it at a write()
38943 + * if yes we can only detect it at a write()
38945 * next step is resetting this attemp and setup a connection again
38948 * if we have more then 5 reconnects for the same request, die
38955 * we have a connection but the child died by some other reason
38960 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
38961 - fdevent_unregister(srv->ev, hctx->fd);
38964 + fdevent_event_del(srv->ev, hctx->sock);
38965 + fdevent_unregister(srv->ev, hctx->sock);
38966 + closesocket(hctx->sock->fd);
38969 - scgi_set_state(srv, hctx, FCGI_STATE_INIT);
38972 + scgi_set_state(srv, hctx, SCGI_STATE_INIT);
38974 hctx->request_id = 0;
38975 hctx->reconnects++;
38978 if (p->conf.debug) {
38979 log_error_write(srv, __FILE__, __LINE__, "sddb",
38984 hctx->proc->pid, hctx->proc->socket);
38988 hctx->proc->load--;
38989 scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
38996 static handler_t scgi_connection_reset(server *srv, connection *con, void *p_d) {
38997 plugin_data *p = p_d;
39000 scgi_connection_cleanup(srv, con->plugin_ctx[p->id]);
39003 return HANDLER_GO_ON;
39007 static int scgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
39011 if (!key || !val) return -1;
39014 len = key_len + val_len + 2;
39017 buffer_prepare_append(env, len);
39019 - /* include the NUL */
39020 + /* include the NUL */
39021 memcpy(env->ptr + env->used, key, key_len + 1);
39022 env->used += key_len + 1;
39023 memcpy(env->ptr + env->used, val, val_len + 1);
39024 env->used += val_len + 1;
39037 @@ -1280,24 +1267,21 @@
39038 struct sockaddr_un scgi_addr_un;
39043 scgi_extension_host *host = hctx->host;
39044 scgi_proc *proc = hctx->proc;
39045 - int scgi_fd = hctx->fd;
39047 + int scgi_fd = hctx->sock->fd;
39049 memset(&scgi_addr, 0, sizeof(scgi_addr));
39052 if (!buffer_is_empty(proc->socket)) {
39053 #ifdef HAVE_SYS_UN_H
39054 /* use the unix domain socket */
39055 scgi_addr_un.sun_family = AF_UNIX;
39056 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
39059 servlen = SUN_LEN(&scgi_addr_un);
39061 - /* stevens says: */
39062 - servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
39065 scgi_addr = (struct sockaddr *) &scgi_addr_un;
39068 @@ -1305,105 +1289,105 @@
39070 scgi_addr_in.sin_family = AF_INET;
39071 if (0 == inet_aton(host->host->ptr, &(scgi_addr_in.sin_addr))) {
39072 - log_error_write(srv, __FILE__, __LINE__, "sbs",
39073 - "converting IP-adress failed for", host->host,
39074 + log_error_write(srv, __FILE__, __LINE__, "sbs",
39075 + "converting IP-adress failed for", host->host,
39076 "\nBe sure to specify an IP address here");
39081 scgi_addr_in.sin_port = htons(proc->port);
39082 servlen = sizeof(scgi_addr_in);
39085 scgi_addr = (struct sockaddr *) &scgi_addr_in;
39089 if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
39090 - if (errno == EINPROGRESS ||
39091 + if (errno == EINPROGRESS ||
39092 errno == EALREADY ||
39094 if (hctx->conf.debug) {
39095 - log_error_write(srv, __FILE__, __LINE__, "sd",
39096 + log_error_write(srv, __FILE__, __LINE__, "sd",
39097 "connect delayed, will continue later:", scgi_fd);
39103 - log_error_write(srv, __FILE__, __LINE__, "sdsddb",
39104 - "connect failed:", scgi_fd,
39105 + log_error_write(srv, __FILE__, __LINE__, "sdsddb",
39106 + "connect failed:", scgi_fd,
39107 strerror(errno), errno,
39108 proc->port, proc->socket);
39110 if (errno == EAGAIN) {
39111 /* this is Linux only */
39113 - log_error_write(srv, __FILE__, __LINE__, "s",
39115 + log_error_write(srv, __FILE__, __LINE__, "s",
39116 "If this happend on Linux: You have been run out of local ports. "
39117 "Check the manual, section Performance how to handle this.");
39125 if (hctx->conf.debug > 1) {
39126 - log_error_write(srv, __FILE__, __LINE__, "sd",
39127 + log_error_write(srv, __FILE__, __LINE__, "sd",
39128 "connect succeeded: ", scgi_fd);
39137 static int scgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
39141 for (i = 0; i < con->request.headers->used; i++) {
39145 ds = (data_string *)con->request.headers->data[i];
39148 if (ds->value->used && ds->key->used) {
39150 buffer_reset(srv->tmp_buf);
39153 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
39154 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
39155 srv->tmp_buf->used--;
39159 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
39160 for (j = 0; j < ds->key->used - 1; j++) {
39161 - srv->tmp_buf->ptr[srv->tmp_buf->used++] =
39162 - light_isalpha(ds->key->ptr[j]) ?
39163 + srv->tmp_buf->ptr[srv->tmp_buf->used++] =
39164 + light_isalpha(ds->key->ptr[j]) ?
39165 ds->key->ptr[j] & ~32 : '_';
39167 srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
39170 scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
39175 for (i = 0; i < con->environment->used; i++) {
39179 ds = (data_string *)con->environment->data[i];
39182 if (ds->value->used && ds->key->used) {
39184 buffer_reset(srv->tmp_buf);
39187 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
39188 for (j = 0; j < ds->key->used - 1; j++) {
39189 - srv->tmp_buf->ptr[srv->tmp_buf->used++] =
39190 - isalpha((unsigned char)ds->key->ptr[j]) ?
39191 + srv->tmp_buf->ptr[srv->tmp_buf->used++] =
39192 + isalpha((unsigned char)ds->key->ptr[j]) ?
39193 toupper((unsigned char)ds->key->ptr[j]) : '_';
39195 srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
39198 scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
39206 @@ -1415,20 +1399,20 @@
39207 char b2[INET6_ADDRSTRLEN + 1];
39212 plugin_data *p = hctx->plugin_data;
39213 scgi_extension_host *host= hctx->host;
39215 connection *con = hctx->remote_conn;
39216 server_socket *srv_sock = con->srv_socket;
39219 sock_addr our_addr;
39220 socklen_t our_addr_len;
39223 buffer_prepare_copy(p->scgi_env, 1024);
39225 /* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
39228 /* request.content_length < SSIZE_MAX, see request.c */
39229 ltostr(buf, con->request.content_length);
39230 scgi_env_add(p->scgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
39231 @@ -1436,13 +1420,13 @@
39234 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
39237 if (con->server_name->used) {
39238 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
39241 - s = inet_ntop(srv_sock->addr.plain.sa_family,
39242 - srv_sock->addr.plain.sa_family == AF_INET6 ?
39243 + s = inet_ntop(srv_sock->addr.plain.sa_family,
39244 + srv_sock->addr.plain.sa_family == AF_INET6 ?
39245 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
39246 (const void *) &(srv_sock->addr.ipv4.sin_addr),
39248 @@ -1451,47 +1435,47 @@
39250 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
39254 scgi_env_add(p->scgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
39260 ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
39262 ntohs(srv_sock->addr.ipv4.sin_port)
39267 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
39270 /* get the server-side of the connection to the client */
39271 our_addr_len = sizeof(our_addr);
39273 - if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
39275 + if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
39276 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
39278 s = inet_ntop_cache_get_ip(srv, &(our_addr));
39280 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
39286 ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
39288 ntohs(con->dst_addr.ipv4.sin_port)
39293 scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
39296 s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
39297 scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
39300 if (!buffer_is_empty(con->authed_user)) {
39301 scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_USER"),
39302 CONST_BUF_LEN(con->authed_user));
39308 * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
39309 @@ -1500,12 +1484,12 @@
39312 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
39315 if (!buffer_is_empty(con->request.pathinfo)) {
39316 scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
39319 /* PATH_TRANSLATED is only defined if PATH_INFO is set */
39322 if (!buffer_is_empty(host->docroot)) {
39323 buffer_copy_string_buffer(p->path, host->docroot);
39325 @@ -1526,19 +1510,19 @@
39328 if (!buffer_is_empty(host->docroot)) {
39330 - * rewrite SCRIPT_FILENAME
39333 + * rewrite SCRIPT_FILENAME
39338 buffer_copy_string_buffer(p->path, host->docroot);
39339 buffer_append_string_buffer(p->path, con->uri.path);
39342 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
39343 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
39345 buffer_copy_string_buffer(p->path, con->physical.path);
39348 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
39349 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
39351 @@ -1551,32 +1535,32 @@
39353 scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
39357 s = get_http_method_name(con->request.http_method);
39358 scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
39359 scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
39360 s = get_http_version_name(con->request.http_version);
39361 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
39365 if (srv_sock->is_ssl) {
39366 scgi_env_add(p->scgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
39371 scgi_env_add_request_headers(srv, con, p);
39373 b = chunkqueue_get_append_buffer(hctx->wb);
39376 buffer_append_long(b, p->scgi_env->used);
39377 buffer_append_string_len(b, CONST_STR_LEN(":"));
39378 buffer_append_string_len(b, (const char *)p->scgi_env->ptr, p->scgi_env->used);
39379 buffer_append_string_len(b, CONST_STR_LEN(","));
39381 hctx->wb->bytes_in += b->used - 1;
39384 if (con->request.content_length) {
39385 - chunkqueue *req_cq = con->request_content_queue;
39386 + chunkqueue *req_cq = con->recv;
39390 @@ -1587,7 +1571,7 @@
39392 /* we announce toWrite octects
39393 * now take all the request_content chunk that we need to fill this request
39397 switch (req_c->type) {
39399 @@ -1615,293 +1599,170 @@
39401 req_c->offset += weHave;
39402 req_cq->bytes_out += weHave;
39405 hctx->wb->bytes_in += weHave;
39419 for (i = 0; i < hctx->write_buffer->used; i++) {
39420 fprintf(stderr, "%02x ", hctx->write_buffer->ptr[i]);
39421 if ((i+1) % 16 == 0) {
39423 for (j = i-15; j <= i; j++) {
39424 - fprintf(stderr, "%c",
39425 + fprintf(stderr, "%c",
39426 isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
39428 fprintf(stderr, "\n");
39436 -static int scgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
39443 - buffer_copy_string_buffer(p->parse_response, in);
39445 - for (s = p->parse_response->ptr;
39446 - NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n')));
39447 - s = ns + (eol == EOL_RN ? 2 : 1), line++) {
39448 - const char *key, *value;
39455 - 0 == strncmp(s, "HTTP/1.", 7)) {
39456 - /* non-parsed header ... we parse them anyway */
39458 - if ((s[7] == '1' ||
39462 - /* after the space should be a status code for us */
39464 - status = strtol(s+9, NULL, 10);
39466 - if (con->http_status >= 100 &&
39467 - con->http_status < 1000) {
39468 - /* we expected 3 digits and didn't got them */
39469 - con->parsed_response |= HTTP_STATUS;
39470 - con->http_status = status;
39476 - if (NULL == (value = strchr(s, ':'))) {
39477 - /* we expect: "<key>: <value>\r\n" */
39481 - key_len = value - key;
39485 - while (*value == ' ' || *value == '\t') value++;
39487 - if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
39488 - ds = data_response_init();
39490 - buffer_copy_string_len(ds->key, key, key_len);
39491 - buffer_copy_string(ds->value, value);
39493 - array_insert_unique(con->response.headers, (data_unset *)ds);
39495 - switch(key_len) {
39497 - if (0 == strncasecmp(key, "Date", key_len)) {
39498 - con->parsed_response |= HTTP_DATE;
39502 - if (0 == strncasecmp(key, "Status", key_len)) {
39503 - con->http_status = strtol(value, NULL, 10);
39504 - con->parsed_response |= HTTP_STATUS;
39508 - if (0 == strncasecmp(key, "Location", key_len)) {
39509 - con->parsed_response |= HTTP_LOCATION;
39513 - if (0 == strncasecmp(key, "Connection", key_len)) {
39514 - con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
39515 - con->parsed_response |= HTTP_CONNECTION;
39519 - if (0 == strncasecmp(key, "Content-Length", key_len)) {
39520 - con->response.content_length = strtol(value, NULL, 10);
39521 - con->parsed_response |= HTTP_CONTENT_LENGTH;
39530 - /* CGI/1.1 rev 03 - 7.2.1.2 */
39531 - if ((con->parsed_response & HTTP_LOCATION) &&
39532 - !(con->parsed_response & HTTP_STATUS)) {
39533 - con->http_status = 302;
39540 static int scgi_demux_response(server *srv, handler_ctx *hctx) {
39541 plugin_data *p = hctx->plugin_data;
39542 connection *con = hctx->remote_conn;
39547 - buffer_prepare_copy(hctx->response, 1024);
39548 - if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
39549 - if (errno == EAGAIN || errno == EINTR) {
39550 - /* would block, wait for signal */
39554 - log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
39559 - /* read finished */
39561 - con->file_finished = 1;
39563 - /* send final chunk */
39564 - http_chunk_append_mem(srv, con, NULL, 0);
39565 - joblist_append(srv, con);
39569 + switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
39570 + case NETWORK_STATUS_SUCCESS:
39571 + /* we got content */
39573 + case NETWORK_STATUS_WAIT_FOR_EVENT:
39574 + /* the ioctl will return WAIT_FOR_EVENT on a read */
39575 + if (0 == con->file_started) return -1;
39576 + case NETWORK_STATUS_CONNECTION_CLOSE:
39577 + /* we are done, get out of here */
39578 + con->send->is_closed = 1;
39580 + /* close the chunk-queue with a empty chunk */
39588 + /* looks like we got some content
39590 + * split off the header from the incoming stream
39593 + if (hctx->state == SCGI_STATE_RESPONSE_HEADER) {
39595 + int have_content_length = 0;
39597 + http_response_reset(p->resp);
39599 + /* the response header is not fully received yet,
39601 + * extract the http-response header from the rb-cq
39603 + switch (http_response_parse_cq(hctx->rb, p->resp)) {
39604 + case PARSE_ERROR:
39605 + /* parsing failed */
39607 + con->http_status = 502; /* Bad Gateway */
39611 - hctx->response->ptr[n] = '\0';
39612 - hctx->response->used = n+1;
39614 - /* split header from body */
39616 - if (con->file_started == 0) {
39618 - int in_header = 0;
39619 - int header_end = 0;
39620 - int cp, eol = EOL_UNSET;
39623 - buffer_append_string_buffer(hctx->response_header, hctx->response);
39625 - /* nph (non-parsed headers) */
39626 - if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
39628 - /* search for the \r\n\r\n or \n\n in the string */
39629 - for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
39630 - if (*c == ':') in_header = 1;
39631 - else if (*c == '\n') {
39632 - if (in_header == 0) {
39633 - /* got a response without a response header */
39640 - if (eol == EOL_UNSET) eol = EOL_N;
39642 - if (*(c+1) == '\n') {
39647 - } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
39648 - if (in_header == 0) {
39649 - /* got a response without a response header */
39656 - if (eol == EOL_UNSET) eol = EOL_RN;
39659 - *(c+2) == '\r' &&
39660 - *(c+3) == '\n') {
39665 - /* skip the \n */
39669 + case PARSE_NEED_MORE:
39671 + case PARSE_SUCCESS:
39672 + con->http_status = p->resp->status;
39674 + chunkqueue_remove_finished_chunks(hctx->rb);
39676 + /* copy the http-headers */
39677 + for (i = 0; i < p->resp->headers->used; i++) {
39678 + const char *ign[] = { "Status", "Connection", NULL };
39682 + data_string *header = (data_string *)p->resp->headers->data[i];
39684 + /* some headers are ignored by default */
39685 + for (j = 0; ign[j]; j++) {
39686 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
39690 - if (header_end) {
39692 - /* no header, but a body */
39694 - if (con->request.http_version == HTTP_VERSION_1_1) {
39695 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
39698 - http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
39699 - joblist_append(srv, con);
39701 - size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
39702 - size_t blen = hctx->response_header->used - hlen - 1;
39704 - /* a small hack: terminate after at the second \r */
39705 - hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
39706 - hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
39708 - /* parse the response header */
39709 - scgi_response_parse(srv, con, p, hctx->response_header, eol);
39711 - /* enable chunked-transfer-encoding */
39712 - if (con->request.http_version == HTTP_VERSION_1_1 &&
39713 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
39714 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
39717 - if ((hctx->response->used != hlen) && blen > 0) {
39718 - http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
39719 - joblist_append(srv, con);
39721 + if (ign[j]) continue;
39723 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
39724 + /* CGI/1.1 rev 03 - 7.2.1.2 */
39725 + if (con->http_status == 0) con->http_status = 302;
39726 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
39727 + have_content_length = 1;
39730 - con->file_started = 1;
39731 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
39732 + ds = data_response_init();
39734 + buffer_copy_string_buffer(ds->key, header->key);
39735 + buffer_copy_string_buffer(ds->value, header->value);
39737 + array_insert_unique(con->response.headers, (data_unset *)ds);
39740 - http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
39741 - joblist_append(srv, con);
39743 + con->file_started = 1;
39745 + if (con->request.http_version == HTTP_VERSION_1_1 &&
39746 + !have_content_length) {
39747 + con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
39750 + hctx->state = SCGI_STATE_RESPONSE_CONTENT;
39755 - log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
39760 + /* FIXME: pass the response-header to the other plugins to
39761 + * setup the filter-queue
39763 + * - use next-queue instead of con->write_queue
39766 + assert(hctx->state == SCGI_STATE_RESPONSE_CONTENT);
39768 + /* FIXME: if we have a content-length or chunked-encoding
39771 + * for now we wait for EOF on the socket */
39773 + /* copy the content to the next cq */
39774 + for (c = hctx->rb->first; c; c = c->next) {
39775 + chunkqueue_append_mem(con->send, c->mem->ptr + c->offset, c->mem->used - c->offset);
39777 + c->offset = c->mem->used - 1;
39780 + chunkqueue_remove_finished_chunks(hctx->rb);
39781 + joblist_append(srv, con);
39787 int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *proc) {
39793 - /* we have been the smallest of the current list
39794 - * and we want to insert the node sorted as soon
39796 + /* we have been the smallest of the current list
39797 + * and we want to insert the node sorted as soon
39810 /* nothing to sort, only one element */
39811 @@ -1909,9 +1770,9 @@
39813 for (p = proc; p->next && p->next->load < proc->load; p = p->next);
39815 - /* no need to move something
39816 + /* no need to move something
39823 @@ -1930,16 +1791,16 @@
39825 if (proc->prev) proc->prev->next = proc->next;
39826 if (proc->next) proc->next->prev = proc->prev;
39829 /* proc should be right of p */
39832 proc->next = p->next;
39834 if (p->next) p->next->prev = proc;
39837 for(p = host->first; p; p = p->next) {
39838 - log_error_write(srv, __FILE__, __LINE__, "dd",
39839 + log_error_write(srv, __FILE__, __LINE__, "dd",
39843 @@ -1951,21 +1812,21 @@
39845 int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *proc) {
39851 - /* we have been the smallest of the current list
39852 - * and we want to insert the node sorted as soon
39854 + /* we have been the smallest of the current list
39855 + * and we want to insert the node sorted as soon
39865 * the basic is idea is:
39866 - * - the last active scgi process should be still
39867 + * - the last active scgi process should be still
39868 * in ram and is not swapped out yet
39869 * - processes that are not reused will be killed
39870 * after some time by the trigger-handler
39871 @@ -1975,7 +1836,7 @@
39872 * ice-cold processes are propably unused since more
39873 * than 'unused-timeout', are swaped out and won't be
39874 * reused in the next seconds anyway.
39879 /* nothing to sort, only one element */
39880 @@ -1984,16 +1845,16 @@
39881 for (p = host->first; p != proc && p->load < proc->load; p = p->next);
39884 - /* no need to move something
39885 + /* no need to move something
39894 if (p == proc) return 0;
39897 /* we have to move left. If we are already the first element
39899 if (host->first == proc) return 0;
39900 @@ -2009,9 +1870,9 @@
39903 if (proc->prev == NULL) host->first = proc;
39906 for(p = host->first; p; p = p->next) {
39907 - log_error_write(srv, __FILE__, __LINE__, "dd",
39908 + log_error_write(srv, __FILE__, __LINE__, "dd",
39912 @@ -2023,41 +1884,42 @@
39914 static int scgi_restart_dead_procs(server *srv, plugin_data *p, scgi_extension_host *host) {
39918 for (proc = host->first; proc; proc = proc->next) {
39919 if (p->conf.debug) {
39920 - log_error_write(srv, __FILE__, __LINE__, "sbdbdddd",
39922 - host->host, proc->port,
39923 + log_error_write(srv, __FILE__, __LINE__, "sbdbdddd",
39925 + host->host, proc->port,
39934 if (0 == proc->is_local) {
39936 - * external servers might get disabled
39938 - * enable the server again, perhaps it is back again
39940 + * external servers might get disabled
39942 + * enable the server again, perhaps it is back again
39946 if ((proc->state == PROC_STATE_DISABLED) &&
39947 (srv->cur_ts - proc->disable_ts > host->disable_time)) {
39948 proc->state = PROC_STATE_RUNNING;
39949 host->active_procs++;
39951 - log_error_write(srv, __FILE__, __LINE__, "sbdb",
39952 - "fcgi-server re-enabled:",
39953 - host->host, host->port,
39955 + log_error_write(srv, __FILE__, __LINE__, "sbdb",
39956 + "fcgi-server re-enabled:",
39957 + host->host, host->port,
39961 /* the child should not terminate at all */
39965 if (proc->state == PROC_STATE_DIED_WAIT_FOR_PID) {
39967 switch(waitpid(proc->pid, &status, WNOHANG)) {
39969 /* child is still alive */
39970 @@ -2067,33 +1929,34 @@
39972 if (WIFEXITED(status)) {
39974 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
39975 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
39976 "child exited, pid:", proc->pid,
39977 "status:", WEXITSTATUS(status));
39979 } else if (WIFSIGNALED(status)) {
39980 - log_error_write(srv, __FILE__, __LINE__, "sd",
39981 - "child signaled:",
39982 + log_error_write(srv, __FILE__, __LINE__, "sd",
39983 + "child signaled:",
39986 - log_error_write(srv, __FILE__, __LINE__, "sd",
39987 - "child died somehow:",
39988 + log_error_write(srv, __FILE__, __LINE__, "sd",
39989 + "child died somehow:",
39994 proc->state = PROC_STATE_DIED;
40003 * local servers might died, but we restart them
40007 if (proc->state == PROC_STATE_DIED &&
40009 /* restart the child */
40012 if (p->conf.debug) {
40013 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
40014 "--- scgi spawning",
40015 @@ -2101,18 +1964,18 @@
40016 "\n\tsocket", host->unixsocket,
40017 "\n\tcurrent:", 1, "/", host->min_procs);
40021 if (scgi_spawn_connection(srv, p, host, proc)) {
40022 log_error_write(srv, __FILE__, __LINE__, "s",
40023 "ERROR: spawning fcgi failed.");
40024 return HANDLER_ERROR;
40028 scgi_proclist_sort_down(srv, host, proc);
40037 @@ -2121,13 +1984,13 @@
40038 plugin_data *p = hctx->plugin_data;
40039 scgi_extension_host *host= hctx->host;
40040 connection *con = hctx->remote_conn;
40045 - /* sanity check */
40046 + /* sanity check */
40048 ((!host->host->used || !host->port) && !host->unixsocket->used)) {
40049 - log_error_write(srv, __FILE__, __LINE__, "sxddd",
40050 + log_error_write(srv, __FILE__, __LINE__, "sxddd",
40051 "write-req: error",
40054 @@ -2135,259 +1998,260 @@
40055 host->unixsocket->used);
40056 return HANDLER_ERROR;
40061 switch(hctx->state) {
40062 - case FCGI_STATE_INIT:
40063 + case SCGI_STATE_INIT:
40064 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
40066 - if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
40068 + if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
40069 if (errno == EMFILE ||
40071 - log_error_write(srv, __FILE__, __LINE__, "sd",
40072 - "wait for fd at connection:", con->fd);
40074 + log_error_write(srv, __FILE__, __LINE__, "sd",
40075 + "wait for fd at connection:", con->sock->fd);
40077 return HANDLER_WAIT_FOR_FD;
40080 - log_error_write(srv, __FILE__, __LINE__, "ssdd",
40082 + log_error_write(srv, __FILE__, __LINE__, "ssdd",
40083 "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
40084 return HANDLER_ERROR;
40086 - hctx->fde_ndx = -1;
40088 + hctx->sock->fde_ndx = -1;
40092 - fdevent_register(srv->ev, hctx->fd, scgi_handle_fdevent, hctx);
40094 - if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
40095 - log_error_write(srv, __FILE__, __LINE__, "ss",
40097 + fdevent_register(srv->ev, hctx->sock, scgi_handle_fdevent, hctx);
40099 + if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
40100 + log_error_write(srv, __FILE__, __LINE__, "ss",
40101 "fcntl failed: ", strerror(errno));
40104 return HANDLER_ERROR;
40109 - case FCGI_STATE_CONNECT:
40110 - if (hctx->state == FCGI_STATE_INIT) {
40111 - for (hctx->proc = hctx->host->first;
40112 - hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
40113 + case SCGI_STATE_CONNECT:
40114 + if (hctx->state == SCGI_STATE_INIT) {
40115 + for (hctx->proc = hctx->host->first;
40116 + hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
40117 hctx->proc = hctx->proc->next);
40120 /* all childs are dead */
40121 if (hctx->proc == NULL) {
40122 - hctx->fde_ndx = -1;
40124 + hctx->sock->fde_ndx = -1;
40126 return HANDLER_ERROR;
40130 if (hctx->proc->is_local) {
40131 hctx->pid = hctx->proc->pid;
40135 switch (scgi_establish_connection(srv, hctx)) {
40137 - scgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
40139 + scgi_set_state(srv, hctx, SCGI_STATE_CONNECT);
40141 /* connection is in progress, wait for an event and call getsockopt() below */
40143 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
40146 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
40148 return HANDLER_WAIT_FOR_EVENT;
40150 /* if ECONNREFUSED choose another connection -> FIXME */
40151 - hctx->fde_ndx = -1;
40153 + hctx->sock->fde_ndx = -1;
40155 return HANDLER_ERROR;
40157 /* everything is ok, go on */
40165 socklen_t socket_error_len = sizeof(socket_error);
40168 /* try to finish the connect() */
40169 - if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
40170 - log_error_write(srv, __FILE__, __LINE__, "ss",
40171 + if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
40172 + log_error_write(srv, __FILE__, __LINE__, "ss",
40173 "getsockopt failed:", strerror(errno));
40176 return HANDLER_ERROR;
40178 if (socket_error != 0) {
40179 if (!hctx->proc->is_local || p->conf.debug) {
40180 /* local procs get restarted */
40183 log_error_write(srv, __FILE__, __LINE__, "ss",
40184 - "establishing connection failed:", strerror(socket_error),
40185 + "establishing connection failed:", strerror(socket_error),
40186 "port:", hctx->proc->port);
40190 return HANDLER_ERROR;
40195 /* ok, we have the connection */
40198 hctx->proc->load++;
40199 hctx->proc->last_used = srv->cur_ts;
40200 hctx->got_proc = 1;
40203 if (p->conf.debug) {
40204 log_error_write(srv, __FILE__, __LINE__, "sddbdd",
40208 - hctx->proc->socket,
40212 + hctx->proc->socket,
40217 /* move the proc-list entry down the list */
40218 scgi_proclist_sort_up(srv, hctx->host, hctx->proc);
40220 - scgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
40222 + scgi_set_state(srv, hctx, SCGI_STATE_PREPARE_WRITE);
40224 - case FCGI_STATE_PREPARE_WRITE:
40225 + case SCGI_STATE_PREPARE_WRITE:
40226 scgi_create_env(srv, hctx);
40228 - scgi_set_state(srv, hctx, FCGI_STATE_WRITE);
40231 + scgi_set_state(srv, hctx, SCGI_STATE_WRITE);
40234 - case FCGI_STATE_WRITE:
40235 - ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
40236 + case SCGI_STATE_WRITE:
40237 + ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
40239 chunkqueue_remove_finished_chunks(hctx->wb);
40243 if (errno == ENOTCONN) {
40244 - /* the connection got dropped after accept()
40246 - * this is most of the time a PHP which dies
40247 + /* the connection got dropped after accept()
40249 + * this is most of the time a PHP which dies
40250 * after PHP_FCGI_MAX_REQUESTS
40255 if (hctx->wb->bytes_out == 0 &&
40256 hctx->reconnects < 5) {
40257 - usleep(10000); /* take away the load of the webserver
40258 - * to let the php a chance to restart
40260 + usleep(10000); /* take away the load of the webserver
40261 + * to let the php a chance to restart
40265 scgi_reconnect(srv, hctx);
40268 return HANDLER_WAIT_FOR_FD;
40272 /* not reconnected ... why
40275 * far@#lighttpd report this for FreeBSD
40280 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
40282 + log_error_write(srv, __FILE__, __LINE__, "ssosd",
40283 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
40284 "write-offset:", hctx->wb->bytes_out,
40285 "reconnect attempts:", hctx->reconnects);
40288 return HANDLER_ERROR;
40292 if ((errno != EAGAIN) &&
40293 (errno != EINTR)) {
40295 - log_error_write(srv, __FILE__, __LINE__, "ssd",
40297 + log_error_write(srv, __FILE__, __LINE__, "ssd",
40298 "write failed:", strerror(errno), errno);
40301 return HANDLER_ERROR;
40303 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
40305 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
40307 return HANDLER_WAIT_FOR_EVENT;
40312 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
40313 /* we don't need the out event anymore */
40314 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
40315 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
40316 - scgi_set_state(srv, hctx, FCGI_STATE_READ);
40317 + fdevent_event_del(srv->ev, hctx->sock);
40318 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
40319 + scgi_set_state(srv, hctx, SCGI_STATE_RESPONSE_HEADER);
40321 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
40323 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
40325 return HANDLER_WAIT_FOR_EVENT;
40330 - case FCGI_STATE_READ:
40331 + case SCGI_STATE_RESPONSE_HEADER:
40332 /* waiting for a response */
40335 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
40336 return HANDLER_ERROR;
40340 return HANDLER_WAIT_FOR_EVENT;
40343 SUBREQUEST_FUNC(mod_scgi_handle_subrequest) {
40344 plugin_data *p = p_d;
40347 handler_ctx *hctx = con->plugin_ctx[p->id];
40349 scgi_extension_host *host;
40352 if (NULL == hctx) return HANDLER_GO_ON;
40356 if (con->mode != p->id) return HANDLER_GO_ON;
40359 /* ok, create the request */
40360 switch(scgi_write_request(srv, hctx)) {
40361 case HANDLER_ERROR:
40368 0 == proc->is_local &&
40369 proc->state != PROC_STATE_DISABLED) {
40370 /* only disable remote servers as we don't manage them*/
40372 - log_error_write(srv, __FILE__, __LINE__, "sbdb", "fcgi-server disabled:",
40374 + log_error_write(srv, __FILE__, __LINE__, "sbdb", "fcgi-server disabled:",
40380 /* disable this server */
40381 proc->disable_ts = srv->cur_ts;
40382 proc->state = PROC_STATE_DISABLED;
40383 host->active_procs--;
40386 - if (hctx->state == FCGI_STATE_INIT ||
40387 - hctx->state == FCGI_STATE_CONNECT) {
40388 - /* connect() or getsockopt() failed,
40389 - * restart the request-handling
40391 + if (hctx->state == SCGI_STATE_INIT ||
40392 + hctx->state == SCGI_STATE_CONNECT) {
40393 + /* connect() or getsockopt() failed,
40394 + * restart the request-handling
40396 if (proc && proc->is_local) {
40398 if (p->conf.debug) {
40399 - log_error_write(srv, __FILE__, __LINE__, "sbdb", "connect() to scgi failed, restarting the request-handling:",
40400 + log_error_write(srv, __FILE__, __LINE__, "sbdb", "connect() to scgi failed, restarting the request-handling:",
40408 * several hctx might reference the same proc
40411 * Only one of them should mark the proc as dead all the other
40412 * ones should just take a new one.
40415 * If a new proc was started with the old struct this might lead
40416 * the mark a perfect proc as dead otherwise
40420 if (proc->state == PROC_STATE_RUNNING &&
40421 hctx->pid == proc->pid) {
40422 @@ -2395,25 +2259,25 @@
40425 scgi_restart_dead_procs(srv, p, host);
40428 scgi_connection_cleanup(srv, hctx);
40431 buffer_reset(con->physical.path);
40432 con->mode = DIRECT;
40433 joblist_append(srv, con);
40435 - /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
40436 - * and hope that the childs will be restarted
40439 + /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
40440 + * and hope that the childs will be restarted
40443 return HANDLER_WAIT_FOR_FD;
40445 scgi_connection_cleanup(srv, hctx);
40448 buffer_reset(con->physical.path);
40449 con->mode = DIRECT;
40450 con->http_status = 503;
40453 return HANDLER_FINISHED;
40455 case HANDLER_WAIT_FOR_EVENT:
40456 @@ -2433,23 +2297,23 @@
40457 static handler_t scgi_connection_close(server *srv, handler_ctx *hctx) {
40462 if (NULL == hctx) return HANDLER_GO_ON;
40465 p = hctx->plugin_data;
40466 con = hctx->remote_conn;
40469 if (con->mode != p->id) return HANDLER_GO_ON;
40471 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
40472 - "emergency exit: scgi:",
40473 - "connection-fd:", con->fd,
40474 - "fcgi-fd:", hctx->fd);
40479 + log_error_write(srv, __FILE__, __LINE__, "ssdsd",
40480 + "emergency exit: scgi:",
40481 + "connection-fd:", con->sock->fd,
40482 + "fcgi-fd:", hctx->sock->fd);
40486 scgi_connection_cleanup(srv, hctx);
40489 return HANDLER_FINISHED;
40492 @@ -2459,27 +2323,28 @@
40493 handler_ctx *hctx = ctx;
40494 connection *con = hctx->remote_conn;
40495 plugin_data *p = hctx->plugin_data;
40498 scgi_proc *proc = hctx->proc;
40499 scgi_extension_host *host= hctx->host;
40501 if ((revents & FDEVENT_IN) &&
40502 - hctx->state == FCGI_STATE_READ) {
40503 + (hctx->state == SCGI_STATE_RESPONSE_HEADER ||
40504 + hctx->state == SCGI_STATE_RESPONSE_CONTENT)) {
40505 switch (scgi_demux_response(srv, hctx)) {
40510 scgi_connection_cleanup(srv, hctx);
40513 joblist_append(srv, con);
40514 return HANDLER_FINISHED;
40516 if (proc->pid && proc->state != PROC_STATE_DIED) {
40520 /* only fetch the zombie if it is not already done */
40523 switch(waitpid(proc->pid, &status, WNOHANG)) {
40525 /* child is still alive */
40526 @@ -2489,19 +2354,19 @@
40528 /* the child should not terminate at all */
40529 if (WIFEXITED(status)) {
40530 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
40531 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
40532 "child exited, pid:", proc->pid,
40533 "status:", WEXITSTATUS(status));
40534 } else if (WIFSIGNALED(status)) {
40535 - log_error_write(srv, __FILE__, __LINE__, "sd",
40536 - "child signaled:",
40537 + log_error_write(srv, __FILE__, __LINE__, "sd",
40538 + "child signaled:",
40541 - log_error_write(srv, __FILE__, __LINE__, "sd",
40542 - "child died somehow:",
40543 + log_error_write(srv, __FILE__, __LINE__, "sd",
40544 + "child died somehow:",
40549 if (p->conf.debug) {
40550 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
40551 "--- scgi spawning",
40552 @@ -2509,117 +2374,118 @@
40553 "\n\tsocket", host->unixsocket,
40554 "\n\tcurrent:", 1, "/", host->min_procs);
40558 if (scgi_spawn_connection(srv, p, host, proc)) {
40560 proc->state = PROC_STATE_DIED;
40562 scgi_proclist_sort_down(srv, host, proc);
40571 if (con->file_started == 0) {
40572 /* nothing has been send out yet, try to use another child */
40575 if (hctx->wb->bytes_out == 0 &&
40576 hctx->reconnects < 5) {
40577 scgi_reconnect(srv, hctx);
40579 - log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
40581 + log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
40582 "response not sent, request not sent, reconnection.",
40583 - "connection-fd:", con->fd,
40584 - "fcgi-fd:", hctx->fd);
40586 + "connection-fd:", con->sock->fd,
40587 + "fcgi-fd:", hctx->sock->fd);
40589 return HANDLER_WAIT_FOR_FD;
40592 - log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
40594 + log_error_write(srv, __FILE__, __LINE__, "sosdsd",
40595 "response not sent, request sent:", hctx->wb->bytes_out,
40596 - "connection-fd:", con->fd,
40597 - "fcgi-fd:", hctx->fd);
40599 + "connection-fd:", con->sock->fd,
40600 + "fcgi-fd:", hctx->sock->fd);
40602 scgi_connection_cleanup(srv, hctx);
40604 - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
40606 buffer_reset(con->physical.path);
40607 con->http_status = 500;
40608 con->mode = DIRECT;
40610 /* response might have been already started, kill the connection */
40611 scgi_connection_cleanup(srv, hctx);
40613 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
40615 + log_error_write(srv, __FILE__, __LINE__, "ssdsd",
40616 "response already sent out, termination connection",
40617 - "connection-fd:", con->fd,
40618 - "fcgi-fd:", hctx->fd);
40620 + "connection-fd:", con->sock->fd,
40621 + "fcgi-fd:", hctx->sock->fd);
40623 connection_set_state(srv, con, CON_STATE_ERROR);
40631 joblist_append(srv, con);
40632 return HANDLER_FINISHED;
40637 if (revents & FDEVENT_OUT) {
40638 - if (hctx->state == FCGI_STATE_CONNECT ||
40639 - hctx->state == FCGI_STATE_WRITE) {
40640 + if (hctx->state == SCGI_STATE_CONNECT ||
40641 + hctx->state == SCGI_STATE_WRITE) {
40642 /* we are allowed to send something out
40645 * 1. in a unfinished connect() call
40646 * 2. in a unfinished write() call (long POST request)
40648 return mod_scgi_handle_subrequest(srv, con, p);
40650 - log_error_write(srv, __FILE__, __LINE__, "sd",
40651 - "got a FDEVENT_OUT and didn't know why:",
40652 + log_error_write(srv, __FILE__, __LINE__, "sd",
40653 + "got a FDEVENT_OUT and didn't know why:",
40659 /* perhaps this issue is already handled */
40660 if (revents & FDEVENT_HUP) {
40661 - if (hctx->state == FCGI_STATE_CONNECT) {
40662 + if (hctx->state == SCGI_STATE_CONNECT) {
40663 /* getoptsock will catch this one (right ?)
40665 - * if we are in connect we might get a EINPROGRESS
40666 - * in the first call and a FDEVENT_HUP in the
40668 + * if we are in connect we might get a EINPROGRESS
40669 + * in the first call and a FDEVENT_HUP in the
40673 * FIXME: as it is a bit ugly.
40677 return mod_scgi_handle_subrequest(srv, con, p);
40678 - } else if (hctx->state == FCGI_STATE_READ &&
40679 + } else if ((hctx->state == SCGI_STATE_RESPONSE_HEADER ||
40680 + hctx->state == SCGI_STATE_RESPONSE_CONTENT ) &&
40681 hctx->proc->port == 0) {
40685 * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
40686 * even if the FCGI_FIN packet is not received yet
40689 - log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
40690 - "error: unexpected close of scgi connection for",
40691 + log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
40692 + "error: unexpected close of scgi connection for",
40694 - "(no scgi process on host: ",
40695 + "(no scgi process on host: ",
40704 connection_set_state(srv, con, CON_STATE_ERROR);
40705 scgi_connection_close(srv, hctx);
40706 joblist_append(srv, con);
40708 } else if (revents & FDEVENT_ERR) {
40709 - log_error_write(srv, __FILE__, __LINE__, "s",
40710 + log_error_write(srv, __FILE__, __LINE__, "s",
40711 "fcgi: got a FDEVENT_ERR. Don't know why.");
40712 /* kill all connections to the scgi process */
40714 @@ -2628,42 +2494,39 @@
40715 scgi_connection_close(srv, hctx);
40716 joblist_append(srv, con);
40720 return HANDLER_FINISHED;
40722 -#define PATCH(x) \
40723 - p->conf.x = s->x;
40725 static int scgi_patch_connection(server *srv, connection *con, plugin_data *p) {
40727 plugin_config *s = p->config_storage[0];
40733 + PATCH_OPTION(exts);
40734 + PATCH_OPTION(debug);
40736 /* skip the first, the global context */
40737 for (i = 1; i < srv->config_context->used; i++) {
40738 data_config *dc = (data_config *)srv->config_context->data[i];
40739 s = p->config_storage[i];
40742 /* condition didn't match */
40743 if (!config_check_cond(srv, con, dc)) continue;
40747 for (j = 0; j < dc->value->used; j++) {
40748 data_unset *du = dc->value->data[j];
40751 if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.server"))) {
40753 + PATCH_OPTION(exts);
40754 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.debug"))) {
40756 + PATCH_OPTION(debug);
40767 static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
40768 plugin_data *p = p_d;
40769 @@ -2673,30 +2536,30 @@
40772 scgi_extension *extension = NULL;
40775 /* Possibly, we processed already this request */
40776 if (con->file_started == 1) return HANDLER_GO_ON;
40779 fn = uri_path_handler ? con->uri.path : con->physical.path;
40781 if (buffer_is_empty(fn)) return HANDLER_GO_ON;
40783 s_len = fn->used - 1;
40786 scgi_patch_connection(srv, con, p);
40788 /* check if extension matches */
40789 for (k = 0; k < p->conf.exts->used; k++) {
40793 extension = p->conf.exts->exts[k];
40796 if (extension->key->used == 0) continue;
40799 ct_len = extension->key->used - 1;
40802 if (s_len < ct_len) continue;
40805 /* check extension in the form "/scgi_pattern" */
40806 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
40808 @@ -2710,17 +2573,17 @@
40809 if (k == p->conf.exts->used) {
40810 return HANDLER_GO_ON;
40814 /* get best server */
40815 for (k = 0, ndx = -1; k < extension->used; k++) {
40816 scgi_extension_host *host = extension->hosts[k];
40819 /* we should have at least one proc that can do somthing */
40820 if (host->active_procs == 0) continue;
40822 if (used == -1 || host->load < used) {
40829 @@ -2728,12 +2591,12 @@
40830 /* found a server */
40832 scgi_extension_host *host = extension->hosts[ndx];
40835 - * if check-local is disabled, use the uri.path handler
40839 + * if check-local is disabled, use the uri.path handler
40844 /* init handler-context */
40845 if (uri_path_handler) {
40846 if (host->check_local == 0) {
40847 @@ -2741,7 +2604,7 @@
40850 hctx = handler_ctx_init();
40853 hctx->remote_conn = con;
40854 hctx->plugin_data = p;
40856 @@ -2749,45 +2612,45 @@
40858 hctx->conf.exts = p->conf.exts;
40859 hctx->conf.debug = p->conf.debug;
40862 con->plugin_ctx[p->id] = hctx;
40870 if (con->conf.log_request_handling) {
40871 log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_scgi");
40874 - /* the prefix is the SCRIPT_NAME,
40875 + /* the prefix is the SCRIPT_NAME,
40876 * everthing from start to the next slash
40877 * this is important for check-local = "disable"
40880 * if prefix = /admin.fcgi
40883 * /admin.fcgi/foo/bar
40886 * SCRIPT_NAME = /admin.fcgi
40887 * PATH_INFO = /foo/bar
40890 * if prefix = /fcgi-bin/
40893 * /fcgi-bin/foo/bar
40896 * SCRIPT_NAME = /fcgi-bin/foo
40903 /* the rewrite is only done for /prefix/? matches */
40904 if (extension->key->ptr[0] == '/' &&
40905 con->uri.path->used > extension->key->used &&
40906 NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
40907 - /* rewrite uri.path and pathinfo */
40909 + /* rewrite uri.path and pathinfo */
40911 buffer_copy_string(con->request.pathinfo, pathinfo);
40914 con->uri.path->used -= con->request.pathinfo->used - 1;
40915 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
40917 @@ -2796,21 +2659,21 @@
40920 hctx = handler_ctx_init();
40923 hctx->remote_conn = con;
40924 hctx->plugin_data = p;
40929 hctx->conf.exts = p->conf.exts;
40930 hctx->conf.debug = p->conf.debug;
40933 con->plugin_ctx[p->id] = hctx;
40942 if (con->conf.log_request_handling) {
40943 log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
40945 @@ -2821,11 +2684,11 @@
40946 /* no handler found */
40947 buffer_reset(con->physical.path);
40948 con->http_status = 500;
40950 - log_error_write(srv, __FILE__, __LINE__, "sb",
40951 - "no fcgi-handler found for:",
40953 + log_error_write(srv, __FILE__, __LINE__, "sb",
40954 + "no fcgi-handler found for:",
40958 return HANDLER_FINISHED;
40960 return HANDLER_GO_ON;
40961 @@ -2844,21 +2707,22 @@
40962 JOBLIST_FUNC(mod_scgi_handle_joblist) {
40963 plugin_data *p = p_d;
40964 handler_ctx *hctx = con->plugin_ctx[p->id];
40967 if (hctx == NULL) return HANDLER_GO_ON;
40969 - if (hctx->fd != -1) {
40970 + if (hctx->sock->fd != -1) {
40971 switch (hctx->state) {
40972 - case FCGI_STATE_READ:
40973 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
40975 + case SCGI_STATE_RESPONSE_HEADER:
40976 + case SCGI_STATE_RESPONSE_CONTENT:
40977 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
40980 - case FCGI_STATE_CONNECT:
40981 - case FCGI_STATE_WRITE:
40982 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
40984 + case SCGI_STATE_CONNECT:
40985 + case SCGI_STATE_WRITE:
40986 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
40989 - case FCGI_STATE_INIT:
40990 + case SCGI_STATE_INIT:
40994 @@ -2873,21 +2737,21 @@
40996 static handler_t scgi_connection_close_callback(server *srv, connection *con, void *p_d) {
40997 plugin_data *p = p_d;
41000 return scgi_connection_close(srv, con->plugin_ctx[p->id]);
41003 TRIGGER_FUNC(mod_scgi_handle_trigger) {
41004 plugin_data *p = p_d;
41010 /* perhaps we should kill a connect attempt after 10-15 seconds
41013 * currently we wait for the TCP timeout which is on Linux 180 seconds
41022 /* check all childs if they are still up */
41023 @@ -2904,47 +2768,47 @@
41024 scgi_extension *ex;
41026 ex = exts->exts[j];
41029 for (n = 0; n < ex->used; n++) {
41033 unsigned long sum_load = 0;
41034 scgi_extension_host *host;
41037 host = ex->hosts[n];
41040 scgi_restart_dead_procs(srv, p, host);
41043 for (proc = host->first; proc; proc = proc->next) {
41044 sum_load += proc->load;
41048 if (host->num_procs &&
41049 host->num_procs < host->max_procs &&
41050 (sum_load / host->num_procs) > host->max_load_per_proc) {
41051 /* overload, spawn new child */
41052 scgi_proc *fp = NULL;
41055 if (p->conf.debug) {
41056 - log_error_write(srv, __FILE__, __LINE__, "s",
41057 + log_error_write(srv, __FILE__, __LINE__, "s",
41058 "overload detected, spawning a new child");
41062 for (fp = host->unused_procs; fp && fp->pid != 0; fp = fp->next);
41066 if (fp == host->unused_procs) host->unused_procs = fp->next;
41069 if (fp->next) fp->next->prev = NULL;
41074 fp = scgi_process_init();
41075 fp->id = host->max_id++;
41082 if (buffer_is_empty(host->unixsocket)) {
41083 fp->port = host->port + fp->id;
41085 @@ -2952,13 +2816,13 @@
41086 buffer_append_string(fp->socket, "-");
41087 buffer_append_long(fp->socket, fp->id);
41091 if (scgi_spawn_connection(srv, p, host, fp)) {
41092 log_error_write(srv, __FILE__, __LINE__, "s",
41093 "ERROR: spawning fcgi failed.");
41094 return HANDLER_ERROR;
41099 fp->next = host->first;
41101 @@ -2966,56 +2830,57 @@
41107 for (proc = host->first; proc; proc = proc->next) {
41108 if (proc->load != 0) break;
41109 if (host->num_procs <= host->min_procs) break;
41110 if (proc->pid == 0) continue;
41113 if (srv->cur_ts - proc->last_used > host->idle_timeout) {
41114 /* a proc is idling for a long time now,
41118 if (p->conf.debug) {
41119 - log_error_write(srv, __FILE__, __LINE__, "ssbsd",
41120 - "idle-timeout reached, terminating child:",
41121 - "socket:", proc->socket,
41122 + log_error_write(srv, __FILE__, __LINE__, "ssbsd",
41123 + "idle-timeout reached, terminating child:",
41124 + "socket:", proc->socket,
41131 if (proc->next) proc->next->prev = proc->prev;
41132 if (proc->prev) proc->prev->next = proc->next;
41135 if (proc->prev == NULL) host->first = proc->next;
41139 proc->next = host->unused_procs;
41142 if (host->unused_procs) host->unused_procs->prev = proc;
41143 host->unused_procs = proc;
41146 kill(proc->pid, SIGTERM);
41149 proc->state = PROC_STATE_KILLED;
41151 - log_error_write(srv, __FILE__, __LINE__, "ssbsd",
41153 - "socket:", proc->socket,
41155 + log_error_write(srv, __FILE__, __LINE__, "ssbsd",
41157 + "socket:", proc->socket,
41164 /* proc is now in unused, let the next second handle the next process */
41172 for (proc = host->unused_procs; proc; proc = proc->next) {
41176 if (proc->pid == 0) continue;
41179 switch (waitpid(proc->pid, &status, WNOHANG)) {
41181 /* child still running after timeout, good */
41182 @@ -3023,10 +2888,10 @@
41184 if (errno != EINTR) {
41185 /* no PID found ? should never happen */
41186 - log_error_write(srv, __FILE__, __LINE__, "sddss",
41187 + log_error_write(srv, __FILE__, __LINE__, "sddss",
41188 "pid ", proc->pid, proc->state,
41189 "not found:", strerror(errno));
41193 if (errno == ECHILD) {
41194 /* someone else has cleaned up for us */
41195 @@ -3040,25 +2905,26 @@
41196 /* the child should not terminate at all */
41197 if (WIFEXITED(status)) {
41198 if (proc->state != PROC_STATE_KILLED) {
41199 - log_error_write(srv, __FILE__, __LINE__, "sdb",
41201 + log_error_write(srv, __FILE__, __LINE__, "sdb",
41203 WEXITSTATUS(status), proc->socket);
41205 } else if (WIFSIGNALED(status)) {
41206 if (WTERMSIG(status) != SIGTERM) {
41207 - log_error_write(srv, __FILE__, __LINE__, "sd",
41208 - "child signaled:",
41209 + log_error_write(srv, __FILE__, __LINE__, "sd",
41210 + "child signaled:",
41214 - log_error_write(srv, __FILE__, __LINE__, "sd",
41215 - "child died somehow:",
41216 + log_error_write(srv, __FILE__, __LINE__, "sd",
41217 + "child died somehow:",
41221 proc->state = PROC_STATE_UNSET;
41228 @@ -3078,12 +2944,14 @@
41229 p->connection_reset = scgi_connection_reset;
41230 p->handle_connection_close = scgi_connection_close_callback;
41231 p->handle_uri_clean = scgi_check_extension_1;
41232 - p->handle_subrequest_start = scgi_check_extension_2;
41233 + p->handle_start_backend = scgi_check_extension_2;
41235 p->handle_subrequest = mod_scgi_handle_subrequest;
41237 p->handle_joblist = mod_scgi_handle_joblist;
41238 p->handle_trigger = mod_scgi_handle_trigger;
41246 --- ../lighttpd-1.4.11/src/mod_secure_download.c 2005-12-14 14:37:29.000000000 +0200
41247 +++ lighttpd-1.5.0/src/mod_secure_download.c 2006-07-16 00:26:03.000000000 +0300
41257 @@ -36,28 +36,28 @@
41260 buffer *uri_prefix;
41263 unsigned short timeout;
41273 plugin_config **config_storage;
41275 - plugin_config conf;
41277 + plugin_config conf;
41280 /* init the plugin data */
41281 INIT_FUNC(mod_secdownload_init) {
41285 p = calloc(1, sizeof(*p));
41288 p->md5 = buffer_init();
41294 @@ -65,27 +65,27 @@
41295 FREE_FUNC(mod_secdownload_free) {
41296 plugin_data *p = p_d;
41300 if (!p) return HANDLER_GO_ON;
41303 if (p->config_storage) {
41305 for (i = 0; i < srv->config_context->used; i++) {
41306 plugin_config *s = p->config_storage[i];
41309 buffer_free(s->secret);
41310 buffer_free(s->doc_root);
41311 buffer_free(s->uri_prefix);
41316 free(p->config_storage);
41320 buffer_free(p->md5);
41326 return HANDLER_GO_ON;
41329 @@ -94,107 +94,103 @@
41330 SETDEFAULTS_FUNC(mod_secdownload_set_defaults) {
41331 plugin_data *p = p_d;
41334 - config_values_t cv[] = {
41336 + config_values_t cv[] = {
41337 { "secdownload.secret", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
41338 { "secdownload.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
41339 { "secdownload.uri-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
41340 { "secdownload.timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
41341 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
41345 if (!p) return HANDLER_ERROR;
41348 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
41351 for (i = 0; i < srv->config_context->used; i++) {
41355 s = calloc(1, sizeof(plugin_config));
41356 s->secret = buffer_init();
41357 s->doc_root = buffer_init();
41358 s->uri_prefix = buffer_init();
41362 cv[0].destination = s->secret;
41363 cv[1].destination = s->doc_root;
41364 cv[2].destination = s->uri_prefix;
41365 cv[3].destination = &(s->timeout);
41368 p->config_storage[i] = s;
41371 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
41372 return HANDLER_ERROR;
41377 return HANDLER_GO_ON;
41381 * checks if the supplied string is a MD5 string
41384 * @param str a possible MD5 string
41385 * @return if the supplied string is a valid MD5 string 1 is returned otherwise 0
41388 int is_hex_len(const char *str, size_t len) {
41392 if (NULL == str) return 0;
41395 for (i = 0; i < len && *str; i++, str++) {
41396 /* illegal characters */
41397 if (!((*str >= '0' && *str <= '9') ||
41398 (*str >= 'a' && *str <= 'f') ||
41399 - (*str >= 'A' && *str <= 'F'))
41400 + (*str >= 'A' && *str <= 'F'))
41410 -#define PATCH(x) \
41411 - p->conf.x = s->x;
41412 static int mod_secdownload_patch_connection(server *srv, connection *con, plugin_data *p) {
41414 plugin_config *s = p->config_storage[0];
41418 - PATCH(uri_prefix);
41422 + PATCH_OPTION(secret);
41423 + PATCH_OPTION(doc_root);
41424 + PATCH_OPTION(uri_prefix);
41425 + PATCH_OPTION(timeout);
41427 /* skip the first, the global context */
41428 for (i = 1; i < srv->config_context->used; i++) {
41429 data_config *dc = (data_config *)srv->config_context->data[i];
41430 s = p->config_storage[i];
41433 /* condition didn't match */
41434 if (!config_check_cond(srv, con, dc)) continue;
41438 for (j = 0; j < dc->value->used; j++) {
41439 data_unset *du = dc->value->data[j];
41442 if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.secret"))) {
41444 + PATCH_OPTION(secret);
41445 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.document-root"))) {
41447 + PATCH_OPTION(doc_root);
41448 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.uri-prefix"))) {
41449 - PATCH(uri_prefix);
41450 + PATCH_OPTION(uri_prefix);
41451 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.timeout"))) {
41453 + PATCH_OPTION(timeout);
41464 URIHANDLER_FUNC(mod_secdownload_uri_handler) {
41465 plugin_data *p = p_d;
41466 @@ -203,88 +199,88 @@
41467 const char *rel_uri, *ts_str, *md5_str;
41472 if (con->uri.path->used == 0) return HANDLER_GO_ON;
41475 mod_secdownload_patch_connection(srv, con, p);
41477 if (buffer_is_empty(p->conf.uri_prefix)) return HANDLER_GO_ON;
41480 if (buffer_is_empty(p->conf.secret)) {
41481 log_error_write(srv, __FILE__, __LINE__, "s",
41482 "secdownload.secret has to be set");
41483 return HANDLER_ERROR;
41487 if (buffer_is_empty(p->conf.doc_root)) {
41488 log_error_write(srv, __FILE__, __LINE__, "s",
41489 "secdownload.document-root has to be set");
41490 return HANDLER_ERROR;
41496 * /<uri-prefix>[a-f0-9]{32}/[a-f0-9]{8}/<rel-path>
41500 if (0 != strncmp(con->uri.path->ptr, p->conf.uri_prefix->ptr, p->conf.uri_prefix->used - 1)) return HANDLER_GO_ON;
41503 md5_str = con->uri.path->ptr + p->conf.uri_prefix->used - 1;
41506 if (!is_hex_len(md5_str, 32)) return HANDLER_GO_ON;
41507 if (*(md5_str + 32) != '/') return HANDLER_GO_ON;
41510 ts_str = md5_str + 32 + 1;
41513 if (!is_hex_len(ts_str, 8)) return HANDLER_GO_ON;
41514 if (*(ts_str + 8) != '/') return HANDLER_GO_ON;
41517 for (i = 0; i < 8; i++) {
41518 ts = (ts << 4) + hex2int(*(ts_str + i));
41523 - if (srv->cur_ts - ts > p->conf.timeout ||
41524 + if (srv->cur_ts - ts > p->conf.timeout ||
41525 srv->cur_ts - ts < -p->conf.timeout) {
41526 con->http_status = 408;
41529 return HANDLER_FINISHED;
41533 rel_uri = ts_str + 8;
41540 * <secret><rel-path><timestamp-hex>
41544 buffer_copy_string_buffer(p->md5, p->conf.secret);
41545 buffer_append_string(p->md5, rel_uri);
41546 buffer_append_string_len(p->md5, ts_str, 8);
41550 MD5_Update(&Md5Ctx, (unsigned char *)p->md5->ptr, p->md5->used - 1);
41551 MD5_Final(HA1, &Md5Ctx);
41554 buffer_copy_string_hex(p->md5, (char *)HA1, 16);
41557 if (0 != strncmp(md5_str, p->md5->ptr, 32)) {
41558 con->http_status = 403;
41560 - log_error_write(srv, __FILE__, __LINE__, "sss",
41562 + log_error_write(srv, __FILE__, __LINE__, "sss",
41564 md5_str, p->md5->ptr);
41567 return HANDLER_FINISHED;
41571 /* starting with the last / we should have relative-path to the docroot
41575 buffer_copy_string_buffer(con->physical.doc_root, p->conf.doc_root);
41576 buffer_copy_string(con->physical.rel_path, rel_uri);
41577 buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
41578 buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
41581 return HANDLER_GO_ON;
41584 @@ -293,13 +289,13 @@
41585 int mod_secdownload_plugin_init(plugin *p) {
41586 p->version = LIGHTTPD_VERSION_ID;
41587 p->name = buffer_init_string("secdownload");
41590 p->init = mod_secdownload_init;
41591 p->handle_physical = mod_secdownload_uri_handler;
41592 p->set_defaults = mod_secdownload_set_defaults;
41593 p->cleanup = mod_secdownload_free;
41601 --- ../lighttpd-1.4.11/src/mod_setenv.c 2006-01-14 20:33:12.000000000 +0200
41602 +++ lighttpd-1.5.0/src/mod_setenv.c 2006-09-07 00:57:05.000000000 +0300
41603 @@ -18,25 +18,25 @@
41605 array *request_header;
41606 array *response_header;
41609 array *environment;
41616 plugin_config **config_storage;
41618 - plugin_config conf;
41620 + plugin_config conf;
41623 static handler_ctx * handler_ctx_init() {
41624 handler_ctx * hctx;
41627 hctx = calloc(1, sizeof(*hctx));
41636 @@ -48,36 +48,36 @@
41637 /* init the plugin data */
41638 INIT_FUNC(mod_setenv_init) {
41642 p = calloc(1, sizeof(*p));
41648 /* detroy the plugin data */
41649 FREE_FUNC(mod_setenv_free) {
41650 plugin_data *p = p_d;
41655 if (!p) return HANDLER_GO_ON;
41658 if (p->config_storage) {
41660 for (i = 0; i < srv->config_context->used; i++) {
41661 plugin_config *s = p->config_storage[i];
41664 array_free(s->request_header);
41665 array_free(s->response_header);
41666 array_free(s->environment);
41671 free(p->config_storage);
41678 return HANDLER_GO_ON;
41681 @@ -86,86 +86,83 @@
41682 SETDEFAULTS_FUNC(mod_setenv_set_defaults) {
41683 plugin_data *p = p_d;
41686 - config_values_t cv[] = {
41688 + config_values_t cv[] = {
41689 { "setenv.add-request-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
41690 { "setenv.add-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
41691 { "setenv.add-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
41692 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
41696 if (!p) return HANDLER_ERROR;
41699 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
41702 for (i = 0; i < srv->config_context->used; i++) {
41706 s = calloc(1, sizeof(plugin_config));
41707 s->request_header = array_init();
41708 s->response_header = array_init();
41709 s->environment = array_init();
41712 cv[0].destination = s->request_header;
41713 cv[1].destination = s->response_header;
41714 cv[2].destination = s->environment;
41717 p->config_storage[i] = s;
41720 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
41721 return HANDLER_ERROR;
41726 return HANDLER_GO_ON;
41729 -#define PATCH(x) \
41730 - p->conf.x = s->x;
41731 static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data *p) {
41733 plugin_config *s = p->config_storage[0];
41735 - PATCH(request_header);
41736 - PATCH(response_header);
41737 - PATCH(environment);
41740 + PATCH_OPTION(request_header);
41741 + PATCH_OPTION(response_header);
41742 + PATCH_OPTION(environment);
41744 /* skip the first, the global context */
41745 for (i = 1; i < srv->config_context->used; i++) {
41746 data_config *dc = (data_config *)srv->config_context->data[i];
41747 s = p->config_storage[i];
41750 /* condition didn't match */
41751 if (!config_check_cond(srv, con, dc)) continue;
41755 for (j = 0; j < dc->value->used; j++) {
41756 data_unset *du = dc->value->data[j];
41759 if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-request-header"))) {
41760 - PATCH(request_header);
41761 + PATCH_OPTION(request_header);
41762 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-response-header"))) {
41763 - PATCH(response_header);
41764 + PATCH_OPTION(response_header);
41765 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-environment"))) {
41766 - PATCH(environment);
41767 + PATCH_OPTION(environment);
41777 URIHANDLER_FUNC(mod_setenv_uri_handler) {
41778 plugin_data *p = p_d;
41783 if (con->plugin_ctx[p->id]) {
41784 hctx = con->plugin_ctx[p->id];
41786 hctx = handler_ctx_init();
41789 con->plugin_ctx[p->id] = hctx;
41792 @@ -180,52 +177,52 @@
41793 for (k = 0; k < p->conf.request_header->used; k++) {
41794 data_string *ds = (data_string *)p->conf.request_header->data[k];
41795 data_string *ds_dst;
41798 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
41799 ds_dst = data_string_init();
41803 buffer_copy_string_buffer(ds_dst->key, ds->key);
41804 buffer_copy_string_buffer(ds_dst->value, ds->value);
41807 array_insert_unique(con->request.headers, (data_unset *)ds_dst);
41811 for (k = 0; k < p->conf.environment->used; k++) {
41812 data_string *ds = (data_string *)p->conf.environment->data[k];
41813 data_string *ds_dst;
41816 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
41817 ds_dst = data_string_init();
41821 buffer_copy_string_buffer(ds_dst->key, ds->key);
41822 buffer_copy_string_buffer(ds_dst->value, ds->value);
41825 array_insert_unique(con->environment, (data_unset *)ds_dst);
41829 for (k = 0; k < p->conf.response_header->used; k++) {
41830 data_string *ds = (data_string *)p->conf.response_header->data[k];
41833 response_header_insert(srv, con, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
41838 return HANDLER_GO_ON;
41841 REQUESTDONE_FUNC(mod_setenv_reset) {
41842 plugin_data *p = p_d;
41848 if (con->plugin_ctx[p->id]) {
41849 handler_ctx_free(con->plugin_ctx[p->id]);
41850 con->plugin_ctx[p->id] = NULL;
41853 - return HANDLER_GO_ON;
41854 + return HANDLER_GO_ON;
41857 /* this function is called at dlopen() time and inits the callbacks */
41858 @@ -233,15 +230,15 @@
41859 int mod_setenv_plugin_init(plugin *p) {
41860 p->version = LIGHTTPD_VERSION_ID;
41861 p->name = buffer_init_string("setenv");
41864 p->init = mod_setenv_init;
41865 p->handle_uri_clean = mod_setenv_uri_handler;
41866 p->set_defaults = mod_setenv_set_defaults;
41867 p->cleanup = mod_setenv_free;
41869 - p->handle_request_done = mod_setenv_reset;
41871 + p->connection_reset = mod_setenv_reset;
41878 --- ../lighttpd-1.4.11/src/mod_simple_vhost.c 2005-11-18 15:16:13.000000000 +0200
41879 +++ lighttpd-1.5.0/src/mod_simple_vhost.c 2006-07-16 00:26:04.000000000 +0300
41882 #include "plugin.h"
41884 +#include "sys-files.h"
41886 #ifdef HAVE_CONFIG_H
41887 #include "config.h"
41890 buffer *server_root;
41891 buffer *default_host;
41892 buffer *document_root;
41895 buffer *docroot_cache_key;
41896 buffer *docroot_cache_value;
41897 buffer *docroot_cache_servername;
41898 @@ -28,138 +30,138 @@
41907 plugin_config **config_storage;
41908 - plugin_config conf;
41909 + plugin_config conf;
41912 INIT_FUNC(mod_simple_vhost_init) {
41916 p = calloc(1, sizeof(*p));
41919 p->doc_root = buffer_init();
41925 FREE_FUNC(mod_simple_vhost_free) {
41926 plugin_data *p = p_d;
41931 if (!p) return HANDLER_GO_ON;
41934 if (p->config_storage) {
41936 for (i = 0; i < srv->config_context->used; i++) {
41937 plugin_config *s = p->config_storage[i];
41940 buffer_free(s->document_root);
41941 buffer_free(s->default_host);
41942 buffer_free(s->server_root);
41945 buffer_free(s->docroot_cache_key);
41946 buffer_free(s->docroot_cache_value);
41947 buffer_free(s->docroot_cache_servername);
41954 free(p->config_storage);
41958 buffer_free(p->doc_root);
41964 return HANDLER_GO_ON;
41967 SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) {
41968 plugin_data *p = p_d;
41971 - config_values_t cv[] = {
41973 + config_values_t cv[] = {
41974 { "simple-vhost.server-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
41975 { "simple-vhost.default-host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
41976 { "simple-vhost.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
41977 { "simple-vhost.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
41978 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
41982 if (!p) return HANDLER_ERROR;
41985 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
41988 for (i = 0; i < srv->config_context->used; i++) {
41992 s = calloc(1, sizeof(plugin_config));
41995 s->server_root = buffer_init();
41996 s->default_host = buffer_init();
41997 s->document_root = buffer_init();
42000 s->docroot_cache_key = buffer_init();
42001 s->docroot_cache_value = buffer_init();
42002 s->docroot_cache_servername = buffer_init();
42007 cv[0].destination = s->server_root;
42008 cv[1].destination = s->default_host;
42009 cv[2].destination = s->document_root;
42010 cv[3].destination = &(s->debug);
42015 p->config_storage[i] = s;
42018 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42019 return HANDLER_ERROR;
42024 return HANDLER_GO_ON;
42027 static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) {
42028 stat_cache_entry *sce = NULL;
42031 buffer_prepare_copy(out, 128);
42033 if (p->conf.server_root->used) {
42034 buffer_copy_string_buffer(out, p->conf.server_root);
42038 /* a hostname has to start with a alpha-numerical character
42039 * and must not contain a slash "/"
42043 - BUFFER_APPEND_SLASH(out);
42046 + PATHNAME_APPEND_SLASH(out);
42048 if (NULL == (dp = strchr(host->ptr, ':'))) {
42049 buffer_append_string_buffer(out, host);
42051 buffer_append_string_len(out, host->ptr, dp - host->ptr);
42054 - BUFFER_APPEND_SLASH(out);
42056 + PATHNAME_APPEND_SLASH(out);
42058 if (p->conf.document_root->used > 2 && p->conf.document_root->ptr[0] == '/') {
42059 buffer_append_string_len(out, p->conf.document_root->ptr + 1, p->conf.document_root->used - 2);
42061 buffer_append_string_buffer(out, p->conf.document_root);
42062 - BUFFER_APPEND_SLASH(out);
42063 + PATHNAME_APPEND_SLASH(out);
42066 buffer_copy_string_buffer(out, con->conf.document_root);
42067 - BUFFER_APPEND_SLASH(out);
42068 + PATHNAME_APPEND_SLASH(out);
42072 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) {
42073 if (p->conf.debug) {
42074 log_error_write(srv, __FILE__, __LINE__, "sb",
42075 @@ -169,57 +171,53 @@
42076 } else if (!S_ISDIR(sce->st.st_mode)) {
42085 -#define PATCH(x) \
42086 - p->conf.x = s->x;
42087 static int mod_simple_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
42089 plugin_config *s = p->config_storage[0];
42091 - PATCH(server_root);
42092 - PATCH(default_host);
42093 - PATCH(document_root);
42095 - PATCH(docroot_cache_key);
42096 - PATCH(docroot_cache_value);
42097 - PATCH(docroot_cache_servername);
42101 + PATCH_OPTION(server_root);
42102 + PATCH_OPTION(default_host);
42103 + PATCH_OPTION(document_root);
42105 + PATCH_OPTION(docroot_cache_key);
42106 + PATCH_OPTION(docroot_cache_value);
42107 + PATCH_OPTION(docroot_cache_servername);
42109 + PATCH_OPTION(debug);
42111 /* skip the first, the global context */
42112 for (i = 1; i < srv->config_context->used; i++) {
42113 data_config *dc = (data_config *)srv->config_context->data[i];
42114 s = p->config_storage[i];
42117 /* condition didn't match */
42118 if (!config_check_cond(srv, con, dc)) continue;
42122 for (j = 0; j < dc->value->used; j++) {
42123 data_unset *du = dc->value->data[j];
42126 if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.server-root"))) {
42127 - PATCH(server_root);
42128 - PATCH(docroot_cache_key);
42129 - PATCH(docroot_cache_value);
42130 - PATCH(docroot_cache_servername);
42131 + PATCH_OPTION(server_root);
42132 + PATCH_OPTION(docroot_cache_key);
42133 + PATCH_OPTION(docroot_cache_value);
42134 + PATCH_OPTION(docroot_cache_servername);
42135 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.default-host"))) {
42136 - PATCH(default_host);
42137 + PATCH_OPTION(default_host);
42138 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.document-root"))) {
42139 - PATCH(document_root);
42140 + PATCH_OPTION(document_root);
42141 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.debug"))) {
42143 + PATCH_OPTION(debug);
42153 static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_data) {
42154 plugin_data *p = p_data;
42155 @@ -227,12 +225,12 @@
42157 * cache the last successfull translation from hostname (authority) to docroot
42158 * - this saves us a stat() call
42164 mod_simple_vhost_patch_connection(srv, con, p);
42166 - if (p->conf.docroot_cache_key->used &&
42168 + if (p->conf.docroot_cache_key->used &&
42169 con->uri.authority->used &&
42170 buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) {
42172 @@ -243,8 +241,8 @@
42173 if ((con->uri.authority->used == 0) ||
42174 build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) {
42175 /* not found, fallback the default-host */
42176 - if (build_doc_root(srv, con, p,
42178 + if (build_doc_root(srv, con, p,
42180 p->conf.default_host)) {
42181 return HANDLER_GO_ON;
42183 @@ -253,15 +251,15 @@
42185 buffer_copy_string_buffer(con->server_name, con->uri.authority);
42189 /* copy to cache */
42190 buffer_copy_string_buffer(p->conf.docroot_cache_key, con->uri.authority);
42191 buffer_copy_string_buffer(p->conf.docroot_cache_value, p->doc_root);
42192 buffer_copy_string_buffer(p->conf.docroot_cache_servername, con->server_name);
42195 buffer_copy_string_buffer(con->physical.doc_root, p->doc_root);
42199 return HANDLER_GO_ON;
42202 @@ -269,13 +267,13 @@
42203 int mod_simple_vhost_plugin_init(plugin *p) {
42204 p->version = LIGHTTPD_VERSION_ID;
42205 p->name = buffer_init_string("simple_vhost");
42208 p->init = mod_simple_vhost_init;
42209 p->set_defaults = mod_simple_vhost_set_defaults;
42210 p->handle_docroot = mod_simple_vhost_docroot;
42211 p->cleanup = mod_simple_vhost_free;
42219 --- ../lighttpd-1.4.11/src/mod_skeleton.c 2005-10-02 18:30:51.000000000 +0300
42220 +++ lighttpd-1.5.0/src/mod_skeleton.c 2006-07-16 00:26:03.000000000 +0300
42221 @@ -14,13 +14,13 @@
42224 * this is a skeleton for a lighttpd plugin
42227 * just replaces every occurance of 'skeleton' by your plugin name
42233 * :%s/skeleton/myhandler/
42239 @@ -33,12 +33,12 @@
42248 plugin_config **config_storage;
42250 - plugin_config conf;
42252 + plugin_config conf;
42256 @@ -47,36 +47,36 @@
42258 static handler_ctx * handler_ctx_init() {
42259 handler_ctx * hctx;
42262 hctx = calloc(1, sizeof(*hctx));
42268 static void handler_ctx_free(handler_ctx *hctx) {
42274 /* init the plugin data */
42275 INIT_FUNC(mod_skeleton_init) {
42279 p = calloc(1, sizeof(*p));
42282 p->match_buf = buffer_init();
42288 /* detroy the plugin data */
42289 FREE_FUNC(mod_skeleton_free) {
42290 plugin_data *p = p_d;
42295 if (!p) return HANDLER_GO_ON;
42298 if (p->config_storage) {
42301 @@ -84,18 +84,18 @@
42302 plugin_config *s = p->config_storage[i];
42307 array_free(s->match);
42312 free(p->config_storage);
42316 buffer_free(p->match_buf);
42322 return HANDLER_GO_ON;
42325 @@ -104,91 +104,88 @@
42326 SETDEFAULTS_FUNC(mod_skeleton_set_defaults) {
42327 plugin_data *p = p_d;
42330 - config_values_t cv[] = {
42332 + config_values_t cv[] = {
42333 { "skeleton.array", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
42334 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42338 if (!p) return HANDLER_ERROR;
42341 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42344 for (i = 0; i < srv->config_context->used; i++) {
42348 s = calloc(1, sizeof(plugin_config));
42349 s->match = array_init();
42352 cv[0].destination = s->match;
42355 p->config_storage[i] = s;
42358 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42359 return HANDLER_ERROR;
42364 return HANDLER_GO_ON;
42367 -#define PATCH(x) \
42368 - p->conf.x = s->x;
42369 static int mod_skeleton_patch_connection(server *srv, connection *con, plugin_data *p) {
42371 plugin_config *s = p->config_storage[0];
42376 + PATCH_OPTION(match);
42378 /* skip the first, the global context */
42379 for (i = 1; i < srv->config_context->used; i++) {
42380 data_config *dc = (data_config *)srv->config_context->data[i];
42381 s = p->config_storage[i];
42384 /* condition didn't match */
42385 if (!config_check_cond(srv, con, dc)) continue;
42389 for (j = 0; j < dc->value->used; j++) {
42390 data_unset *du = dc->value->data[j];
42393 if (buffer_is_equal_string(du->key, CONST_STR_LEN("skeleton.array"))) {
42395 + PATCH_OPTION(match);
42405 URIHANDLER_FUNC(mod_skeleton_uri_handler) {
42406 plugin_data *p = p_d;
42413 if (con->uri.path->used == 0) return HANDLER_GO_ON;
42416 mod_skeleton_patch_connection(srv, con, p);
42418 s_len = con->uri.path->used - 1;
42421 for (k = 0; k < p->conf.match->used; k++) {
42422 data_string *ds = (data_string *)p->conf.match->data[k];
42423 int ct_len = ds->value->used - 1;
42426 if (ct_len > s_len) continue;
42427 if (ds->value->used == 0) continue;
42430 if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
42431 con->http_status = 403;
42434 return HANDLER_FINISHED;
42440 return HANDLER_GO_ON;
42442 @@ -198,13 +195,13 @@
42443 int mod_skeleton_plugin_init(plugin *p) {
42444 p->version = LIGHTTPD_VERSION_ID;
42445 p->name = buffer_init_string("skeleton");
42448 p->init = mod_skeleton_init;
42449 p->handle_uri_clean = mod_skeleton_uri_handler;
42450 p->set_defaults = mod_skeleton_set_defaults;
42451 p->cleanup = mod_skeleton_free;
42459 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.c 1970-01-01 03:00:00.000000000 +0300
42460 +++ lighttpd-1.5.0/src/mod_sql_vhost_core.c 2006-07-20 00:57:20.000000000 +0300
42462 +#include <stdio.h>
42463 +#include <errno.h>
42464 +#include <fcntl.h>
42465 +#include <string.h>
42467 +#ifdef HAVE_CONFIG_H
42468 +#include "config.h"
42471 +#include "plugin.h"
42474 +#include "stat_cache.h"
42476 +#include "mod_sql_vhost_core.h"
42478 +#define plugin_data mod_sql_vhost_core_plugin_data
42479 +#define plugin_config mod_sql_vhost_core_plugin_config
42481 +/* init the plugin data */
42482 +INIT_FUNC(mod_sql_vhost_core_init) {
42485 + p = calloc(1, sizeof(*p));
42487 + p->docroot = buffer_init();
42488 + p->host = buffer_init();
42493 +/* cleanup the plugin data */
42494 +SERVER_FUNC(mod_sql_vhost_core_cleanup) {
42495 + plugin_data *p = p_d;
42499 + if (!p) return HANDLER_GO_ON;
42501 + if (p->config_storage) {
42503 + for (i = 0; i < srv->config_context->used; i++) {
42504 + plugin_config *s = p->config_storage[i];
42506 + if (!s) continue;
42508 + buffer_free(s->db);
42509 + buffer_free(s->user);
42510 + buffer_free(s->pass);
42511 + buffer_free(s->sock);
42512 + buffer_free(s->backend);
42513 + buffer_free(s->hostname);
42514 + buffer_free(s->select_vhost);
42518 + free(p->config_storage);
42520 + buffer_free(p->docroot);
42521 + buffer_free(p->host);
42525 + return HANDLER_GO_ON;
42528 +/* set configuration values */
42529 +SERVER_FUNC(mod_sql_vhost_core_set_defaults) {
42530 + plugin_data *p = p_d;
42534 + config_values_t cv[] = {
42535 + { "sql-vhost.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 0 * e.g. vhost */
42536 + { "sql-vhost.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 1 * lighty */
42537 + { "sql-vhost.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 2 * secrect */
42538 + { "sql-vhost.sock", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 3 * /tmp/mysql.sock */
42539 + { "sql-vhost.select-vhost", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 4 * SELECT ... FROM hosts WHERE hostname = ? */
42540 + { "sql-vhost.hostname", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 5 * 127.0.0.1 */
42541 + { "sql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 6 * 3306 */
42542 + { "sql-vhost.backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 7 * mysql */
42544 + /* backward compat */
42545 + { "mysql-vhost.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 8 == 0 */
42546 + { "mysql-vhost.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 9 == 1 */
42547 + { "mysql-vhost.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 10 == 2 */
42548 + { "mysql-vhost.sock", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 11 == 3 */
42549 + { "mysql-vhost.sql", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 12 == 4 */
42550 + { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER }, /* 13 == 5 */
42551 + { "mysql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 14 == 6 */
42553 + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42556 + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42558 + for (i = 0; i < srv->config_context->used; i++) {
42559 + plugin_config *s;
42561 + s = calloc(1, sizeof(plugin_config));
42562 + s->db = buffer_init();
42563 + s->user = buffer_init();
42564 + s->pass = buffer_init();
42565 + s->sock = buffer_init();
42566 + s->hostname = buffer_init();
42567 + s->backend = buffer_init();
42568 + s->port = 0; /* default port for mysql */
42569 + s->select_vhost = buffer_init();
42570 + s->backend_data = NULL;
42572 + cv[0].destination = s->db;
42573 + cv[1].destination = s->user;
42574 + cv[2].destination = s->pass;
42575 + cv[3].destination = s->sock;
42576 + cv[4].destination = s->select_vhost;
42577 + cv[5].destination = s->hostname;
42578 + cv[6].destination = &(s->port);
42579 + cv[7].destination = s->backend;
42581 + /* backend compat */
42582 + cv[8].destination = cv[0].destination;
42583 + cv[9].destination = cv[1].destination;
42584 + cv[10].destination = cv[2].destination;
42585 + cv[11].destination = cv[3].destination;
42586 + cv[12].destination = cv[4].destination;
42587 + cv[13].destination = cv[5].destination;
42588 + cv[14].destination = cv[6].destination;
42590 + p->config_storage[i] = s;
42592 + if (config_insert_values_global(srv,
42593 + ((data_config *)srv->config_context->data[i])->value,
42594 + cv)) return HANDLER_ERROR;
42596 + /* we only parse the config, the backend plugin will patch itself into the plugin-struct */
42599 + return HANDLER_GO_ON;
42602 +static int mod_sql_vhost_core_patch_connection(server *srv, connection *con, plugin_data *p) {
42604 + plugin_config *s = p->config_storage[0];
42606 + PATCH_OPTION(backend_data);
42607 + PATCH_OPTION(get_vhost);
42609 + /* skip the first, the global context */
42610 + for (i = 1; i < srv->config_context->used; i++) {
42611 + data_config *dc = (data_config *)srv->config_context->data[i];
42612 + s = p->config_storage[i];
42614 + /* condition didn't match */
42615 + if (!config_check_cond(srv, con, dc)) continue;
42617 + if (s->backend_data) {
42618 + PATCH_OPTION(backend_data);
42619 + PATCH_OPTION(get_vhost);
42626 +/* handle document root request */
42627 +CONNECTION_FUNC(mod_sql_vhost_core_handle_docroot) {
42628 + plugin_data *p = p_d;
42629 + stat_cache_entry *sce;
42631 + /* no host specified? */
42632 + if (!con->uri.authority->used) return HANDLER_GO_ON;
42634 + mod_sql_vhost_core_patch_connection(srv, con, p);
42636 + /* do we have backend ? */
42637 + if (!p->conf.get_vhost) return HANDLER_GO_ON;
42639 + /* ask the backend for the data */
42640 + if (0 != p->conf.get_vhost(srv, con, p->conf.backend_data, p->docroot, p->host)) {
42641 + return HANDLER_GO_ON;
42644 + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->docroot, &sce)) {
42645 + log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->docroot);
42646 + return HANDLER_GO_ON;
42648 + if (!S_ISDIR(sce->st.st_mode)) {
42649 + log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->docroot);
42650 + return HANDLER_GO_ON;
42653 + buffer_copy_string_buffer(con->server_name, p->host);
42654 + buffer_copy_string_buffer(con->physical.doc_root, p->docroot);
42656 + return HANDLER_GO_ON;
42659 +/* this function is called at dlopen() time and inits the callbacks */
42660 +int mod_sql_vhost_core_plugin_init(plugin *p) {
42661 + p->version = LIGHTTPD_VERSION_ID;
42662 + p->name = buffer_init_string("mod_sql_vhost_core");
42664 + p->init = mod_sql_vhost_core_init;
42665 + p->cleanup = mod_sql_vhost_core_cleanup;
42667 + p->set_defaults = mod_sql_vhost_core_set_defaults;
42668 + p->handle_docroot = mod_sql_vhost_core_handle_docroot;
42673 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.h 1970-01-01 03:00:00.000000000 +0300
42674 +++ lighttpd-1.5.0/src/mod_sql_vhost_core.h 2006-07-16 00:26:04.000000000 +0300
42676 +#ifndef _MOD_SQL_VHOST_CORE_H_
42677 +#define _MOD_SQL_VHOST_CORE_H_
42679 +#include "buffer.h"
42680 +#include "plugin.h"
42682 +#define SQLVHOST_BACKEND_GETVHOST_PARAMS \
42683 + (server *srv, connection *con, void *p_d, buffer *docroot, buffer *host)
42685 +#define SQLVHOST_BACKEND_GETVHOST_RETVAL handler_t
42687 +#define SQLVHOST_BACKEND_GETVHOST(name) \
42688 + SQLVHOST_BACKEND_GETVHOST_RETVAL name SQLVHOST_BACKEND_GETVHOST_PARAMS
42690 +#define SQLVHOST_BACKEND_GETVHOST_PTR(name) \
42691 + SQLVHOST_BACKEND_GETVHOST_RETVAL (* name)SQLVHOST_BACKEND_GETVHOST_PARAMS
42699 + buffer *hostname;
42700 + unsigned short port;
42703 + void *backend_data;
42705 + buffer *select_vhost;
42707 + SQLVHOST_BACKEND_GETVHOST_PTR(get_vhost);
42708 +} mod_sql_vhost_core_plugin_config;
42710 +/* global plugin data */
42717 + mod_sql_vhost_core_plugin_config **config_storage;
42719 + mod_sql_vhost_core_plugin_config conf;
42720 +} mod_sql_vhost_core_plugin_data;
42725 --- ../lighttpd-1.4.11/src/mod_ssi.c 2006-03-04 17:09:48.000000000 +0200
42726 +++ lighttpd-1.5.0/src/mod_ssi.c 2006-09-07 00:57:05.000000000 +0300
42728 #include <string.h>
42731 -#include <unistd.h>
42736 #include "inet_ntop_cache.h"
42738 #include "sys-socket.h"
42739 +#include "sys-strings.h"
42740 +#include "sys-files.h"
42744 @@ -39,15 +40,15 @@
42745 /* init the plugin data */
42746 INIT_FUNC(mod_ssi_init) {
42750 p = calloc(1, sizeof(*p));
42753 p->timefmt = buffer_init();
42754 p->stat_fn = buffer_init();
42757 p->ssi_vars = array_init();
42758 p->ssi_cgi_env = array_init();
42764 @@ -55,21 +56,21 @@
42765 FREE_FUNC(mod_ssi_free) {
42766 plugin_data *p = p_d;
42770 if (!p) return HANDLER_GO_ON;
42773 if (p->config_storage) {
42775 for (i = 0; i < srv->config_context->used; i++) {
42776 plugin_config *s = p->config_storage[i];
42779 array_free(s->ssi_extension);
42784 free(p->config_storage);
42788 array_free(p->ssi_vars);
42789 array_free(p->ssi_cgi_env);
42793 buffer_free(p->timefmt);
42794 buffer_free(p->stat_fn);
42800 return HANDLER_GO_ON;
42803 @@ -92,36 +93,36 @@
42804 const char *errptr;
42808 - config_values_t cv[] = {
42810 + config_values_t cv[] = {
42811 { "ssi.extension", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
42812 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42816 if (!p) return HANDLER_ERROR;
42819 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42822 for (i = 0; i < srv->config_context->used; i++) {
42826 s = calloc(1, sizeof(plugin_config));
42827 s->ssi_extension = array_init();
42830 cv[0].destination = s->ssi_extension;
42833 p->config_storage[i] = s;
42836 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42837 return HANDLER_ERROR;
42843 /* allow 2 params */
42844 if (NULL == (p->ssi_regex = pcre_compile("<!--#([a-z]+)\\s+(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?-->", 0, &errptr, &erroff, NULL))) {
42845 log_error_write(srv, __FILE__, __LINE__, "sds",
42849 return HANDLER_ERROR;
42851 @@ -130,52 +131,52 @@
42852 "mod_ssi: pcre support is missing, please recompile with pcre support or remove mod_ssi from the list of modules");
42853 return HANDLER_ERROR;
42857 return HANDLER_GO_ON;
42860 int ssi_env_add(array *env, const char *key, const char *val) {
42864 if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
42865 ds = data_string_init();
42867 buffer_copy_string(ds->key, key);
42868 buffer_copy_string(ds->value, val);
42871 array_insert_unique(env, (data_unset *)ds);
42879 * the next two functions are take from fcgi.c
42884 static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
42888 for (i = 0; i < con->request.headers->used; i++) {
42892 ds = (data_string *)con->request.headers->data[i];
42895 if (ds->value->used && ds->key->used) {
42897 buffer_reset(srv->tmp_buf);
42900 /* don't forward the Authorization: Header */
42901 if (0 == strcasecmp(ds->key->ptr, "AUTHORIZATION")) {
42906 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
42907 buffer_copy_string(srv->tmp_buf, "HTTP_");
42908 srv->tmp_buf->used--;
42912 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
42913 for (j = 0; j < ds->key->used - 1; j++) {
42915 @@ -189,33 +190,33 @@
42916 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
42918 srv->tmp_buf->ptr[srv->tmp_buf->used] = '\0';
42921 ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
42929 static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
42933 server_socket *srv_sock = con->srv_socket;
42937 char b2[INET6_ADDRSTRLEN + 1];
42940 #define CONST_STRING(x) \
42944 array_reset(p->ssi_cgi_env);
42947 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_SOFTWARE"), PACKAGE_NAME"/"PACKAGE_VERSION);
42948 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_NAME"),
42950 - inet_ntop(srv_sock->addr.plain.sa_family,
42951 - srv_sock->addr.plain.sa_family == AF_INET6 ?
42952 + inet_ntop(srv_sock->addr.plain.sa_family,
42953 + srv_sock->addr.plain.sa_family == AF_INET6 ?
42954 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
42955 (const void *) &(srv_sock->addr.ipv4.sin_addr),
42957 @@ -224,28 +225,28 @@
42960 ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1");
42966 ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
42968 ntohs(srv_sock->addr.ipv4.sin_port)
42973 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PORT"), buf);
42976 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_ADDR"),
42977 inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
42980 if (con->authed_user->used) {
42981 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_USER"),
42982 con->authed_user->ptr);
42986 if (con->request.content_length > 0) {
42987 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
42990 /* request.content_length < SSIZE_MAX, see request.c */
42991 ltostr(buf, con->request.content_length);
42992 ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf);
42993 @@ -271,30 +272,30 @@
42994 if (con->request.pathinfo->used) {
42995 ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), con->request.pathinfo->ptr);
42999 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_FILENAME"), con->physical.path->ptr);
43000 ssi_env_add(p->ssi_cgi_env, CONST_STRING("DOCUMENT_ROOT"), con->physical.doc_root->ptr);
43003 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_URI"), con->request.uri->ptr);
43004 ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), con->uri.query->used ? con->uri.query->ptr : "");
43005 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method));
43006 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200");
43007 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version));
43010 ssi_env_add_request_headers(srv, con, p);
43016 -static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
43017 +static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
43018 const char **l, size_t n) {
43019 size_t i, ssicmd = 0;
43027 - enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
43028 + enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
43029 SSI_CONFIG, SSI_PRINTENV, SSI_SET, SSI_IF, SSI_ELIF,
43030 SSI_ELSE, SSI_ENDIF, SSI_EXEC } type;
43032 @@ -310,27 +311,27 @@
43033 { "endif", SSI_ENDIF },
43034 { "else", SSI_ELSE },
43035 { "exec", SSI_EXEC },
43038 { NULL, SSI_UNSET }
43042 for (i = 0; ssicmds[i].var; i++) {
43043 if (0 == strcmp(l[1], ssicmds[i].var)) {
43044 ssicmd = ssicmds[i].type;
43053 int var = 0, enc = 0;
43054 const char *var_val = NULL;
43055 stat_cache_entry *sce = NULL;
43061 - enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
43062 + enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
43063 SSI_ECHO_LAST_MODIFIED, SSI_ECHO_USER_NAME } type;
43065 { "DATE_GMT", SSI_ECHO_DATE_GMT },
43066 @@ -339,27 +340,27 @@
43067 { "DOCUMENT_URI", SSI_ECHO_DOCUMENT_URI },
43068 { "LAST_MODIFIED", SSI_ECHO_LAST_MODIFIED },
43069 { "USER_NAME", SSI_ECHO_USER_NAME },
43072 { NULL, SSI_ECHO_UNSET }
43079 enum { SSI_ENC_UNSET, SSI_ENC_URL, SSI_ENC_NONE, SSI_ENC_ENTITY } type;
43081 { "url", SSI_ENC_URL },
43082 { "none", SSI_ENC_NONE },
43083 { "entity", SSI_ENC_ENTITY },
43086 { NULL, SSI_ENC_UNSET }
43090 for (i = 2; i < n; i += 2) {
43091 if (0 == strcmp(l[i], "var")) {
43098 for (j = 0; echovars[j].var; j++) {
43099 if (0 == strcmp(l[i+1], echovars[j].var)) {
43100 var = echovars[j].type;
43101 @@ -368,7 +369,7 @@
43103 } else if (0 == strcmp(l[i], "encoding")) {
43107 for (j = 0; encvars[j].var; j++) {
43108 if (0 == strcmp(l[i+1], encvars[j].var)) {
43109 enc = encvars[j].type;
43110 @@ -377,27 +378,27 @@
43113 log_error_write(srv, __FILE__, __LINE__, "sss",
43114 - "ssi: unknow attribute for ",
43115 + "ssi: unknow attribute for ",
43121 if (p->if_is_false) break;
43125 log_error_write(srv, __FILE__, __LINE__, "sss",
43128 l[1], "var is missing");
43132 stat_cache_get_entry(srv, con, con->physical.path, &sce);
43136 case SSI_ECHO_USER_NAME: {
43139 - b = chunkqueue_get_append_buffer(con->write_queue);
43141 + b = chunkqueue_get_append_buffer(con->send);
43143 if (NULL == (pw = getpwuid(sce->st.st_uid))) {
43144 buffer_copy_long(b, sce->st.st_uid);
43145 @@ -411,8 +412,8 @@
43147 case SSI_ECHO_LAST_MODIFIED: {
43148 time_t t = sce->st.st_mtime;
43150 - b = chunkqueue_get_append_buffer(con->write_queue);
43152 + b = chunkqueue_get_append_buffer(con->send);
43153 if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
43154 buffer_copy_string(b, "(none)");
43156 @@ -422,8 +423,8 @@
43158 case SSI_ECHO_DATE_LOCAL: {
43159 time_t t = time(NULL);
43161 - b = chunkqueue_get_append_buffer(con->write_queue);
43163 + b = chunkqueue_get_append_buffer(con->send);
43164 if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
43165 buffer_copy_string(b, "(none)");
43167 @@ -433,8 +434,8 @@
43169 case SSI_ECHO_DATE_GMT: {
43170 time_t t = time(NULL);
43172 - b = chunkqueue_get_append_buffer(con->write_queue);
43174 + b = chunkqueue_get_append_buffer(con->send);
43175 if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
43176 buffer_copy_string(b, "(none)");
43178 @@ -444,8 +445,8 @@
43180 case SSI_ECHO_DOCUMENT_NAME: {
43183 - b = chunkqueue_get_append_buffer(con->write_queue);
43185 + b = chunkqueue_get_append_buffer(con->send);
43186 if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
43187 buffer_copy_string_buffer(b, con->physical.path);
43189 @@ -454,22 +455,22 @@
43192 case SSI_ECHO_DOCUMENT_URI: {
43193 - b = chunkqueue_get_append_buffer(con->write_queue);
43194 + b = chunkqueue_get_append_buffer(con->send);
43195 buffer_copy_string_buffer(b, con->uri.path);
43200 /* check if it is a cgi-var */
43202 - b = chunkqueue_get_append_buffer(con->write_queue);
43205 + b = chunkqueue_get_append_buffer(con->send);
43207 if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) {
43208 buffer_copy_string_buffer(b, ds->value);
43210 buffer_copy_string(b, "(none)");
43217 @@ -481,7 +482,7 @@
43218 const char * file_path = NULL, *virt_path = NULL;
43223 for (i = 2; i < n; i += 2) {
43224 if (0 == strcmp(l[i], "file")) {
43225 file_path = l[i+1];
43226 @@ -489,28 +490,28 @@
43227 virt_path = l[i+1];
43229 log_error_write(srv, __FILE__, __LINE__, "sss",
43230 - "ssi: unknow attribute for ",
43231 + "ssi: unknow attribute for ",
43237 if (!file_path && !virt_path) {
43238 log_error_write(srv, __FILE__, __LINE__, "sss",
43241 l[1], "file or virtual are missing");
43246 if (file_path && virt_path) {
43247 log_error_write(srv, __FILE__, __LINE__, "sss",
43250 l[1], "only one of file and virtual is allowed here");
43257 if (p->if_is_false) break;
43261 /* current doc-root */
43262 if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
43263 @@ -519,46 +520,46 @@
43264 buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1);
43267 - buffer_copy_string(srv->tmp_buf, file_path);
43268 + buffer_copy_string(srv->tmp_buf, file_path);
43269 buffer_urldecode_path(srv->tmp_buf);
43270 - buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
43271 - buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
43272 + buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
43273 + buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
43278 if (virt_path[0] == '/') {
43279 buffer_copy_string(p->stat_fn, virt_path);
43281 /* there is always a / */
43282 sl = strrchr(con->uri.path->ptr, '/');
43285 buffer_copy_string_len(p->stat_fn, con->uri.path->ptr, sl - con->uri.path->ptr + 1);
43286 buffer_append_string(p->stat_fn, virt_path);
43290 buffer_urldecode_path(p->stat_fn);
43291 buffer_path_simplify(srv->tmp_buf, p->stat_fn);
43294 /* we have an uri */
43297 buffer_copy_string_buffer(p->stat_fn, con->physical.doc_root);
43298 buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
43302 if (0 == stat(p->stat_fn->ptr, &st)) {
43303 time_t t = st.st_mtime;
43308 - b = chunkqueue_get_append_buffer(con->write_queue);
43309 + b = chunkqueue_get_append_buffer(con->send);
43312 const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };
43315 off_t s = st.st_size;
43318 for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);
43321 buffer_copy_off_t(b, s);
43322 buffer_append_string(b, abr[j]);
43324 @@ -566,7 +567,7 @@
43328 - b = chunkqueue_get_append_buffer(con->write_queue);
43329 + b = chunkqueue_get_append_buffer(con->send);
43330 if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
43331 buffer_copy_string(b, "(none)");
43333 @@ -574,12 +575,12 @@
43337 - chunkqueue_append_file(con->write_queue, p->stat_fn, 0, st.st_size);
43338 + chunkqueue_append_file(con->send, p->stat_fn, 0, st.st_size);
43342 log_error_write(srv, __FILE__, __LINE__, "sbs",
43343 - "ssi: stating failed ",
43344 + "ssi: stating failed ",
43345 p->stat_fn, strerror(errno));
43348 @@ -593,33 +594,33 @@
43351 log_error_write(srv, __FILE__, __LINE__, "sss",
43352 - "ssi: unknow attribute for ",
43353 + "ssi: unknow attribute for ",
43359 if (p->if_is_false) break;
43366 if (NULL == (ds = (data_string *)array_get_unused_element(p->ssi_vars, TYPE_STRING))) {
43367 ds = data_string_init();
43369 buffer_copy_string(ds->key, key);
43370 buffer_copy_string(ds->value, val);
43373 array_insert_unique(p->ssi_vars, (data_unset *)ds);
43375 log_error_write(srv, __FILE__, __LINE__, "sss",
43376 - "ssi: var and value have to be set in",
43377 + "ssi: var and value have to be set in",
43384 if (p->if_is_false) break;
43387 for (i = 2; i < n; i += 2) {
43388 if (0 == strcmp(l[i], "timefmt")) {
43389 buffer_copy_string(p->timefmt, l[i+1]);
43390 @@ -632,63 +633,65 @@
43391 log_error_write(srv, __FILE__, __LINE__, "sssss",
43392 "ssi: unknow value for attribute '",
43399 log_error_write(srv, __FILE__, __LINE__, "sss",
43400 - "ssi: unknow attribute for ",
43401 + "ssi: unknow attribute for ",
43407 if (p->if_is_false) break;
43409 - b = chunkqueue_get_append_buffer(con->write_queue);
43411 + b = chunkqueue_get_append_buffer(con->send);
43412 buffer_copy_string(b, "<pre>");
43413 for (i = 0; i < p->ssi_vars->used; i++) {
43414 data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]];
43417 buffer_append_string_buffer(b, ds->key);
43418 buffer_append_string(b, ": ");
43419 buffer_append_string_buffer(b, ds->value);
43420 buffer_append_string(b, "<br />");
43424 buffer_append_string(b, "</pre>");
43431 const char *cmd = NULL;
43433 int from_exec_fds[2];
43436 for (i = 2; i < n; i += 2) {
43437 if (0 == strcmp(l[i], "cmd")) {
43440 log_error_write(srv, __FILE__, __LINE__, "sss",
43441 - "ssi: unknow attribute for ",
43442 + "ssi: unknow attribute for ",
43448 if (p->if_is_false) break;
43451 /* create a return pipe and send output to the html-page
43453 - * as exec is assumed evil it is implemented synchronously
43455 + * as exec is assumed evil it is implemented synchronously
43462 if (pipe(from_exec_fds)) {
43463 - log_error_write(srv, __FILE__, __LINE__, "ss",
43464 + log_error_write(srv, __FILE__, __LINE__, "ss",
43465 "pipe failed: ", strerror(errno));
43471 switch (pid = fork()) {
43473 @@ -698,14 +701,14 @@
43474 close(from_exec_fds[1]);
43476 close(from_exec_fds[0]);
43480 close(STDIN_FILENO);
43483 execl("/bin/sh", "sh", "-c", cmd, NULL);
43486 log_error_write(srv, __FILE__, __LINE__, "sss", "spawing exec failed:", strerror(errno), cmd);
43492 @@ -718,9 +721,9 @@
43498 close(from_exec_fds[1]);
43501 /* wait for the client to end */
43502 if (-1 == waitpid(pid, &status, 0)) {
43503 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
43504 @@ -730,18 +733,18 @@
43507 if (ioctl(from_exec_fds[0], FIONREAD, &toread)) {
43508 - log_error_write(srv, __FILE__, __LINE__, "s",
43509 + log_error_write(srv, __FILE__, __LINE__, "s",
43510 "unexpected end-of-file (perhaps the ssi-exec process died)");
43515 - b = chunkqueue_get_append_buffer(con->write_queue);
43516 + b = chunkqueue_get_append_buffer(con->send);
43518 - buffer_prepare_copy(b, toread + 1);
43519 + buffer_prepare_copy(b, toread + 1);
43521 if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
43522 - /* read failed */
43523 + /* read failed */
43527 @@ -755,59 +758,58 @@
43528 log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally");
43530 close(from_exec_fds[0]);
43545 const char *expr = NULL;
43548 for (i = 2; i < n; i += 2) {
43549 if (0 == strcmp(l[i], "expr")) {
43552 log_error_write(srv, __FILE__, __LINE__, "sss",
43553 - "ssi: unknow attribute for ",
43554 + "ssi: unknow attribute for ",
43561 log_error_write(srv, __FILE__, __LINE__, "sss",
43564 l[1], "expr missing");
43569 if ((!p->if_is_false) &&
43570 - ((p->if_is_false_level == 0) ||
43571 + ((p->if_is_false_level == 0) ||
43572 (p->if_level < p->if_is_false_level))) {
43573 switch (ssi_eval_expr(srv, con, p, expr)) {
43576 - p->if_is_false = 1;
43578 + p->if_is_false = 1;
43579 p->if_is_false_level = p->if_level;
43582 - p->if_is_false = 0;
43584 + p->if_is_false = 0;
43599 if (p->if_is_false) {
43600 if ((p->if_level == p->if_is_false_level) &&
43601 (p->if_is_false_endif == 0)) {
43602 @@ -815,11 +817,11 @@
43605 p->if_is_false = 1;
43608 p->if_is_false_level = p->if_level;
43615 const char *expr = NULL;
43616 @@ -828,52 +830,52 @@
43619 log_error_write(srv, __FILE__, __LINE__, "sss",
43620 - "ssi: unknow attribute for ",
43621 + "ssi: unknow attribute for ",
43628 log_error_write(srv, __FILE__, __LINE__, "sss",
43631 l[1], "expr missing");
43639 if (p->if_level == p->if_is_false_level) {
43640 if ((p->if_is_false) &&
43641 (p->if_is_false_endif == 0)) {
43642 switch (ssi_eval_expr(srv, con, p, expr)) {
43645 - p->if_is_false = 1;
43647 + p->if_is_false = 1;
43648 p->if_is_false_level = p->if_level;
43651 - p->if_is_false = 0;
43653 + p->if_is_false = 0;
43657 - p->if_is_false = 1;
43658 + p->if_is_false = 1;
43659 p->if_is_false_level = p->if_level;
43660 p->if_is_false_endif = 1;
43674 if (p->if_level == p->if_is_false_level) {
43675 p->if_is_false = 0;
43676 p->if_is_false_endif = 0;
43682 log_error_write(srv, __FILE__, __LINE__, "ss",
43683 @@ -881,41 +883,41 @@
43694 static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) {
43705 /* get a stream to the file */
43708 array_reset(p->ssi_vars);
43709 array_reset(p->ssi_cgi_env);
43710 buffer_copy_string(p->timefmt, "%a, %d %b %Y %H:%M:%S %Z");
43712 build_ssi_cgi_vars(srv, con, p);
43713 p->if_is_false = 0;
43716 if (-1 == stream_open(&s, con->physical.path)) {
43717 log_error_write(srv, __FILE__, __LINE__, "sb",
43718 "stream-open: ", con->physical.path);
43726 - * <!--#element attribute=value attribute=value ... -->
43728 + * <!--#element attribute=value attribute=value ... -->
43731 - * errmsg -- missing
43732 + * errmsg -- missing
43736 @@ -937,13 +939,13 @@
43753 @@ -951,118 +953,115 @@
43765 - * The current date in Greenwich Mean Time.
43767 - * The current date in the local time zone.
43769 - * The filename (excluding directories) of the document requested by the user.
43771 - * 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.
43773 - * The last modification date of the document requested by the user.
43776 + * The current date in Greenwich Mean Time.
43778 + * The current date in the local time zone.
43780 + * The filename (excluding directories) of the document requested by the user.
43782 + * 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.
43784 + * The last modification date of the document requested by the user.
43786 * Contains the owner of the file which included it.
43790 -#ifdef HAVE_PCRE_H
43791 +#ifdef HAVE_PCRE_H
43792 for (i = 0; (n = pcre_exec(p->ssi_regex, NULL, s.start, s.size, i, 0, ovec, N * 3)) > 0; i = ovec[1]) {
43794 /* take everything from last offset to current match pos */
43796 - if (!p->if_is_false) chunkqueue_append_file(con->write_queue, con->physical.path, i, ovec[0] - i);
43799 + if (!p->if_is_false) chunkqueue_append_file(con->send, con->physical.path, i, ovec[0] - i);
43801 pcre_get_substring_list(s.start, ovec, n, &l);
43802 process_ssi_stmt(srv, con, p, l, n);
43803 pcre_free_substring_list(l);
43808 case PCRE_ERROR_NOMATCH:
43809 /* copy everything/the rest */
43810 - chunkqueue_append_file(con->write_queue, con->physical.path, i, s.size - i);
43812 + chunkqueue_append_file(con->send, con->physical.path, i, s.size - i);
43816 log_error_write(srv, __FILE__, __LINE__, "sd",
43817 "execution error while matching: ", n);
43829 con->file_started = 1;
43830 - con->file_finished = 1;
43832 + con->send->is_closed = 1;
43834 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
43837 /* reset physical.path */
43838 buffer_reset(con->physical.path);
43844 -#define PATCH(x) \
43845 - p->conf.x = s->x;
43846 static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p) {
43848 plugin_config *s = p->config_storage[0];
43850 - PATCH(ssi_extension);
43853 + PATCH_OPTION(ssi_extension);
43855 /* skip the first, the global context */
43856 for (i = 1; i < srv->config_context->used; i++) {
43857 data_config *dc = (data_config *)srv->config_context->data[i];
43858 s = p->config_storage[i];
43861 /* condition didn't match */
43862 if (!config_check_cond(srv, con, dc)) continue;
43866 for (j = 0; j < dc->value->used; j++) {
43867 data_unset *du = dc->value->data[j];
43870 if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.extension"))) {
43871 - PATCH(ssi_extension);
43872 + PATCH_OPTION(ssi_extension);
43882 URIHANDLER_FUNC(mod_ssi_physical_path) {
43883 plugin_data *p = p_d;
43887 if (con->physical.path->used == 0) return HANDLER_GO_ON;
43890 mod_ssi_patch_connection(srv, con, p);
43893 for (k = 0; k < p->conf.ssi_extension->used; k++) {
43894 data_string *ds = (data_string *)p->conf.ssi_extension->data[k];
43897 if (ds->value->used == 0) continue;
43900 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
43901 /* handle ssi-request */
43904 if (mod_ssi_handle_request(srv, con, p)) {
43906 con->http_status = 500;
43910 return HANDLER_FINISHED;
43916 return HANDLER_GO_ON;
43918 @@ -1072,13 +1071,13 @@
43919 int mod_ssi_plugin_init(plugin *p) {
43920 p->version = LIGHTTPD_VERSION_ID;
43921 p->name = buffer_init_string("ssi");
43924 p->init = mod_ssi_init;
43925 - p->handle_subrequest_start = mod_ssi_physical_path;
43926 + p->handle_start_backend = mod_ssi_physical_path;
43927 p->set_defaults = mod_ssi_set_defaults;
43928 p->cleanup = mod_ssi_free;
43936 --- ../lighttpd-1.4.11/src/mod_ssi.h 2005-08-11 01:26:39.000000000 +0300
43937 +++ lighttpd-1.5.0/src/mod_ssi.h 2006-07-16 00:26:04.000000000 +0300
43938 @@ -19,23 +19,23 @@
43943 -#ifdef HAVE_PCRE_H
43945 +#ifdef HAVE_PCRE_H
43957 array *ssi_cgi_env;
43960 int if_level, if_is_false_level, if_is_false, if_is_false_endif;
43963 plugin_config **config_storage;
43965 - plugin_config conf;
43967 + plugin_config conf;
43970 int ssi_eval_expr(server *srv, connection *con, plugin_data *p, const char *expr);
43971 --- ../lighttpd-1.4.11/src/mod_ssi_expr.c 2005-08-11 01:26:48.000000000 +0300
43972 +++ lighttpd-1.5.0/src/mod_ssi_expr.c 2006-07-16 00:26:04.000000000 +0300
43985 @@ -21,15 +21,15 @@
43987 ssi_val_t *ssi_val_init() {
43991 s = calloc(1, sizeof(*s));
43997 void ssi_val_free(ssi_val_t *s) {
43998 if (s->str) buffer_free(s->str);
44004 @@ -45,175 +45,175 @@
44005 ssi_tokenizer_t *t, int *token_id, buffer *token) {
44012 for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
44013 char c = t->input[t->offset];
44027 buffer_copy_string(token, "(=)");
44032 if (t->input[t->offset + 1] == '=') {
44040 buffer_copy_string(token, "(>=)");
44049 buffer_copy_string(token, "(>)");
44055 if (t->input[t->offset + 1] == '=') {
44063 buffer_copy_string(token, "(<=)");
44072 buffer_copy_string(token, "(<)");
44080 if (t->input[t->offset + 1] == '=') {
44088 buffer_copy_string(token, "(!=)");
44097 buffer_copy_string(token, "(!)");
44103 if (t->input[t->offset + 1] == '&') {
44111 buffer_copy_string(token, "(&&)");
44113 - log_error_write(srv, __FILE__, __LINE__, "sds",
44114 - "pos:", t->line_pos,
44115 + log_error_write(srv, __FILE__, __LINE__, "sds",
44116 + "pos:", t->line_pos,
44117 "missing second &");
44124 if (t->input[t->offset + 1] == '|') {
44132 buffer_copy_string(token, "(||)");
44134 - log_error_write(srv, __FILE__, __LINE__, "sds",
44135 - "pos:", t->line_pos,
44136 + log_error_write(srv, __FILE__, __LINE__, "sds",
44137 + "pos:", t->line_pos,
44138 "missing second |");
44152 /* search for the terminating " */
44153 for (i = 1; t->input[t->offset + i] && t->input[t->offset + i] != '\''; i++);
44156 if (t->input[t->offset + i]) {
44160 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
44163 t->offset += i + 1;
44164 t->line_pos += i + 1;
44168 - log_error_write(srv, __FILE__, __LINE__, "sds",
44169 - "pos:", t->line_pos,
44171 + log_error_write(srv, __FILE__, __LINE__, "sds",
44172 + "pos:", t->line_pos,
44173 "missing closing quote");
44189 buffer_copy_string(token, "(");
44199 buffer_copy_string(token, ")");
44202 if (t->input[t->offset + 1] == '{') {
44203 for (i = 2; t->input[t->offset + i] && t->input[t->offset + i] != '}'; i++);
44206 if (t->input[t->offset + i] != '}') {
44207 - log_error_write(srv, __FILE__, __LINE__, "sds",
44208 - "pos:", t->line_pos,
44209 + log_error_write(srv, __FILE__, __LINE__, "sds",
44210 + "pos:", t->line_pos,
44211 "missing closing quote");
44218 buffer_copy_string_len(token, t->input + t->offset + 2, i-3);
44220 for (i = 1; isalpha(t->input[t->offset + i]) || t->input[t->offset + i] == '_'; i++);
44223 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
44230 if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, token->ptr))) {
44231 buffer_copy_string_buffer(token, ds->value);
44232 } else if (NULL != (ds = (data_string *)array_get_element(p->ssi_vars, token->ptr))) {
44233 @@ -221,16 +221,16 @@
44235 buffer_copy_string(token, "");
44245 for (i = 0; isgraph(t->input[t->offset + i]); i++) {
44246 char d = t->input[t->offset + i];
44253 @@ -244,25 +244,25 @@
44262 buffer_copy_string_len(token, t->input + t->offset, i);
44279 } else if (t->offset < t->size) {
44280 - log_error_write(srv, __FILE__, __LINE__, "sds",
44281 - "pos:", t->line_pos,
44282 + log_error_write(srv, __FILE__, __LINE__, "sds",
44283 + "pos:", t->line_pos,
44287 @@ -275,50 +275,50 @@
44295 t.size = strlen(expr);
44308 /* default context */
44311 pParser = ssiexprparserAlloc( malloc );
44312 token = buffer_init();
44313 while((1 == (ret = ssi_expr_tokenizer(srv, con, p, &t, &token_id, token))) && context.ok) {
44314 ssiexprparser(pParser, token_id, token, &context);
44317 token = buffer_init();
44319 ssiexprparser(pParser, 0, token, &context);
44320 ssiexprparserFree(pParser, free );
44323 buffer_free(token);
44327 - log_error_write(srv, __FILE__, __LINE__, "s",
44328 + log_error_write(srv, __FILE__, __LINE__, "s",
44329 "expr parser failed");
44334 if (context.ok == 0) {
44335 - log_error_write(srv, __FILE__, __LINE__, "sds",
44336 - "pos:", t.line_pos,
44337 + log_error_write(srv, __FILE__, __LINE__, "sds",
44338 + "pos:", t.line_pos,
44339 "parser failed somehow near here");
44343 - log_error_write(srv, __FILE__, __LINE__, "ssd",
44344 + log_error_write(srv, __FILE__, __LINE__, "ssd",
44350 return context.val.bo;
44352 --- ../lighttpd-1.4.11/src/mod_ssi_expr.h 2005-08-11 01:26:48.000000000 +0300
44353 +++ lighttpd-1.5.0/src/mod_ssi_expr.h 2006-07-16 00:26:04.000000000 +0300
44357 enum { SSI_TYPE_UNSET, SSI_TYPE_BOOL, SSI_TYPE_STRING } type;
44374 --- ../lighttpd-1.4.11/src/mod_ssi_exprparser.c 2005-10-03 00:40:25.000000000 +0300
44375 +++ lighttpd-1.5.0/src/mod_ssi_exprparser.c 2006-07-17 22:02:23.000000000 +0300
44376 @@ -18,10 +18,10 @@
44377 /* Next is all token values, in a form suitable for use by makeheaders.
44378 ** This section will be null unless lemon is run with the -m switch.
44382 ** These constants (all generated automatically by the parser generator)
44383 ** specify the various kinds of tokens (terminals) that the parser
44387 ** Each symbol here is a terminal symbol in the grammar.
44390 ** and nonterminals. "int" is used otherwise.
44391 ** YYNOCODE is a number of type YYCODETYPE which corresponds
44392 ** to no legal terminal or nonterminal number. This
44393 -** number is used to fill in empty slots of the hash
44394 +** number is used to fill in empty slots of the hash
44396 ** YYFALLBACK If defined, this indicates that one or more tokens
44397 ** have fall-back values which should be used if the
44399 ** and nonterminal numbers. "unsigned char" is
44400 ** used if there are fewer than 250 rules and
44401 ** states combined. "int" is used otherwise.
44402 -** ssiexprparserTOKENTYPE is the data type used for minor tokens given
44403 +** ssiexprparserTOKENTYPE is the data type used for minor tokens given
44404 ** directly to the parser from the tokenizer.
44405 ** YYMINORTYPE is the data type used for all minor tokens.
44406 ** This is typically a union of many types, one of
44408 /* Next are that tables used to determine what action to take based on the
44409 ** current state and lookahead token. These tables are used to implement
44410 ** functions that take a state number and lookahead value and return an
44411 -** action integer.
44412 +** action integer.
44414 ** Suppose the action integer is N. Then the action is determined as
44416 @@ -116,7 +116,7 @@
44417 ** If the index value yy_shift_ofst[S]+X is out of range or if the value
44418 ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
44419 ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
44420 -** and that yy_default[S] should be used instead.
44421 +** and that yy_default[S] should be used instead.
44423 ** The formula above is for computing the action when the lookahead is
44424 ** a terminal symbol. If the lookahead is a non-terminal (as occurs after
44425 @@ -168,7 +168,7 @@
44427 /* The next table maps tokens into fallback tokens. If a construct
44428 ** like the following:
44431 ** %fallback ID X Y Z.
44433 ** appears in the grammer, then ID becomes a fallback token for X, Y,
44434 @@ -219,10 +219,10 @@
44435 #endif /* NDEBUG */
44440 ** Turn parser tracing on by giving a stream to which to write the trace
44441 ** and a prompt to preface each trace message. Tracing is turned off
44442 -** by making either argument NULL
44443 +** by making either argument NULL
44447 @@ -247,7 +247,7 @@
44449 /* For tracing shifts, the names of all terminals and nonterminals
44450 ** are required. The following table supplies these names */
44451 -static const char *yyTokenName[] = {
44452 +static const char *yyTokenName[] = {
44453 "$", "AND", "OR", "EQ",
44454 "NE", "GT", "GE", "LT",
44455 "LE", "NOT", "LPARAN", "RPARAN",
44456 @@ -295,7 +295,7 @@
44462 ** This function allocates a new parser.
44463 ** The only argument is a pointer to a function which works like
44465 @@ -326,7 +326,7 @@
44466 /* Here is inserted the actions which take place when a
44467 ** terminal or non-terminal is destroyed. This can happen
44468 ** when the symbol is popped from the stack during a
44469 - ** reduce or during error processing or when a parser is
44470 + ** reduce or during error processing or when a parser is
44471 ** being destroyed before it is finished parsing.
44473 ** Note: during a reduce, the only symbols destroyed are those
44474 @@ -379,7 +379,7 @@
44480 ** Deallocate and destroy a parser. Destructors are all called for
44481 ** all stack elements before shutting the parser down.
44483 @@ -415,7 +415,7 @@
44486 int stateno = pParser->yystack[pParser->yyidx].stateno;
44489 /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
44490 i = yy_shift_ofst[stateno];
44491 if( i==YY_SHIFT_USE_DFLT ){
44492 @@ -459,7 +459,7 @@
44495 int stateno = pParser->yystack[pParser->yyidx].stateno;
44498 i = yy_reduce_ofst[stateno];
44499 if( i==YY_REDUCE_USE_DFLT ){
44500 return yy_default[stateno];
44501 @@ -559,7 +559,7 @@
44502 ssiexprparserARG_FETCH;
44503 yymsp = &yypParser->yystack[yypParser->yyidx];
44505 - if( yyTraceFILE && yyruleno>=0
44506 + if( yyTraceFILE && yyruleno>=0
44507 && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
44508 fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
44509 yyRuleName[yyruleno]);
44510 @@ -872,7 +872,7 @@
44511 #ifdef YYERRORSYMBOL
44512 /* A syntax error has occurred.
44513 ** The response to an error depends upon whether or not the
44514 - ** grammar defines an error token "ERROR".
44515 + ** grammar defines an error token "ERROR".
44517 ** This is what we do if the grammar does define ERROR:
44519 --- ../lighttpd-1.4.11/src/mod_staticfile.c 2006-02-15 14:31:14.000000000 +0200
44520 +++ lighttpd-1.5.0/src/mod_staticfile.c 2006-09-07 00:57:05.000000000 +0300
44521 @@ -11,12 +11,15 @@
44523 #include "stat_cache.h"
44525 -#include "http_chunk.h"
44526 #include "response.h"
44528 +#include "sys-files.h"
44529 +#include "sys-strings.h"
44531 +#include "http_req_range.h"
44533 * this is a staticfile for a lighttpd plugin
44539 @@ -29,48 +32,48 @@
44548 plugin_config **config_storage;
44550 - plugin_config conf;
44552 + plugin_config conf;
44555 /* init the plugin data */
44556 INIT_FUNC(mod_staticfile_init) {
44560 p = calloc(1, sizeof(*p));
44563 p->range_buf = buffer_init();
44569 -/* detroy the plugin data */
44570 +/* destroy the plugin data */
44571 FREE_FUNC(mod_staticfile_free) {
44572 plugin_data *p = p_d;
44577 if (!p) return HANDLER_GO_ON;
44580 if (p->config_storage) {
44582 for (i = 0; i < srv->config_context->used; i++) {
44583 plugin_config *s = p->config_storage[i];
44586 array_free(s->exclude_ext);
44591 free(p->config_storage);
44593 buffer_free(p->range_buf);
44599 return HANDLER_GO_ON;
44602 @@ -79,263 +82,222 @@
44603 SETDEFAULTS_FUNC(mod_staticfile_set_defaults) {
44604 plugin_data *p = p_d;
44607 - config_values_t cv[] = {
44609 + config_values_t cv[] = {
44610 { "static-file.exclude-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
44611 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
44615 if (!p) return HANDLER_ERROR;
44618 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
44621 for (i = 0; i < srv->config_context->used; i++) {
44625 s = calloc(1, sizeof(plugin_config));
44626 s->exclude_ext = array_init();
44629 cv[0].destination = s->exclude_ext;
44632 p->config_storage[i] = s;
44635 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
44636 return HANDLER_ERROR;
44641 return HANDLER_GO_ON;
44644 -#define PATCH(x) \
44645 - p->conf.x = s->x;
44646 static int mod_staticfile_patch_connection(server *srv, connection *con, plugin_data *p) {
44648 plugin_config *s = p->config_storage[0];
44650 - PATCH(exclude_ext);
44653 + PATCH_OPTION(exclude_ext);
44655 /* skip the first, the global context */
44656 for (i = 1; i < srv->config_context->used; i++) {
44657 data_config *dc = (data_config *)srv->config_context->data[i];
44658 s = p->config_storage[i];
44661 /* condition didn't match */
44662 if (!config_check_cond(srv, con, dc)) continue;
44666 for (j = 0; j < dc->value->used; j++) {
44667 data_unset *du = dc->value->data[j];
44670 if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.exclude-extensions"))) {
44671 - PATCH(exclude_ext);
44672 + PATCH_OPTION(exclude_ext);
44682 static int http_response_parse_range(server *srv, connection *con, plugin_data *p) {
44685 - off_t start, end;
44686 - const char *s, *minus;
44687 char *boundary = "fkj49sn38dcn3";
44689 stat_cache_entry *sce = NULL;
44690 buffer *content_type = NULL;
44692 + buffer *range = NULL;
44693 + http_req_range *ranges, *r;
44695 + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Range"))) {
44696 + range = ds->value;
44698 + /* we don't have a Range header */
44703 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
44708 - end = sce->st.st_size - 1;
44711 con->response.content_length = 0;
44714 if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {
44715 content_type = ds->value;
44718 - for (s = con->request.http_range, error = 0;
44719 - !error && *s && NULL != (minus = strchr(s, '-')); ) {
44723 - if (s == minus) {
44726 - le = strtoll(s, &err, 10);
44729 - /* RFC 2616 - 14.35.1 */
44731 - con->http_status = 416;
44733 - } else if (*err == '\0') {
44737 - end = sce->st.st_size - 1;
44738 - start = sce->st.st_size + le;
44739 - } else if (*err == ',') {
44743 - end = sce->st.st_size - 1;
44744 - start = sce->st.st_size + le;
44749 - } else if (*(minus+1) == '\0' || *(minus+1) == ',') {
44752 - la = strtoll(s, &err, 10);
44754 - if (err == minus) {
44757 - if (*(err + 1) == '\0') {
44760 - end = sce->st.st_size - 1;
44763 - } else if (*(err + 1) == ',') {
44767 - end = sce->st.st_size - 1;
44777 - /* <start>-<stop> */
44779 - la = strtoll(s, &err, 10);
44781 - if (err == minus) {
44782 - le = strtoll(minus+1, &err, 10);
44784 - /* RFC 2616 - 14.35.1 */
44789 - if (*err == '\0') {
44795 - } else if (*err == ',') {
44804 + /* start the range-header parser
44807 + ranges = http_request_range_init();
44808 + switch (http_request_range_parse(range, ranges)) {
44809 + case PARSE_ERROR:
44810 + return -1; /* no range valid Range Header */
44811 + case PARSE_SUCCESS:
44814 + TRACE("%s", "foobar");
44818 + if (ranges->next) {
44822 + /* patch the '-1' */
44823 + for (r = ranges; r; r = r->next) {
44824 + if (r->start == -1) {
44827 + * the last <end> bytes */
44828 + r->start = sce->st.st_size - r->end;
44829 + r->end = sce->st.st_size - 1;
44831 + if (r->end == -1) {
44833 + * all but the first <start> bytes */
44842 + r->end = sce->st.st_size - 1;
44846 - if (start < 0) start = 0;
44848 - /* RFC 2616 - 14.35.1 */
44849 - if (end > sce->st.st_size - 1) end = sce->st.st_size - 1;
44851 - if (start > sce->st.st_size - 1) {
44854 - con->http_status = 416;
44857 + if (r->end > sce->st.st_size - 1) {
44858 + /* RFC 2616 - 14.35.1
44860 + * if last-byte-pos not present or > size-of-file
44861 + * take the size-of-file
44864 + r->end = sce->st.st_size - 1;
44869 - /* write boundary-header */
44872 - b = chunkqueue_get_append_buffer(con->write_queue);
44874 - buffer_copy_string(b, "\r\n--");
44875 - buffer_append_string(b, boundary);
44877 - /* write Content-Range */
44878 - buffer_append_string(b, "\r\nContent-Range: bytes ");
44879 - buffer_append_off_t(b, start);
44880 - buffer_append_string(b, "-");
44881 - buffer_append_off_t(b, end);
44882 - buffer_append_string(b, "/");
44883 - buffer_append_off_t(b, sce->st.st_size);
44885 - buffer_append_string(b, "\r\nContent-Type: ");
44886 - buffer_append_string_buffer(b, content_type);
44888 - /* write END-OF-HEADER */
44889 - buffer_append_string(b, "\r\n\r\n");
44891 - con->response.content_length += b->used - 1;
44895 - chunkqueue_append_file(con->write_queue, con->physical.path, start, end - start + 1);
44896 - con->response.content_length += end - start + 1;
44898 + if (r->start > sce->st.st_size - 1) {
44899 + /* RFC 2616 - 14.35.1
44901 + * if first-byte-pos > file-size, 416
44904 + con->http_status = 416;
44908 + if (r->start > r->end) {
44909 + /* RFC 2616 - 14.35.1
44911 + * if last-byte-pos is present, it has to be >= first-byte-pos
44913 + * invalid ranges have to be handle as no Range specified
44920 - /* something went wrong */
44921 - if (error) return -1;
44925 + /* we ran into an range violation */
44930 - /* add boundary end */
44933 - b = chunkqueue_get_append_buffer(con->write_queue);
44935 + for (r = ranges; r; r = r->next) {
44936 + /* write boundary-header */
44938 + b = chunkqueue_get_append_buffer(con->send);
44940 + buffer_copy_string(b, "\r\n--");
44941 + buffer_append_string(b, boundary);
44943 + /* write Content-Range */
44944 + buffer_append_string(b, "\r\nContent-Range: bytes ");
44945 + buffer_append_off_t(b, r->start);
44946 + buffer_append_string(b, "-");
44947 + buffer_append_off_t(b, r->end);
44948 + buffer_append_string(b, "/");
44949 + buffer_append_off_t(b, sce->st.st_size);
44951 + buffer_append_string(b, "\r\nContent-Type: ");
44952 + buffer_append_string_buffer(b, content_type);
44954 + /* write END-OF-HEADER */
44955 + buffer_append_string(b, "\r\n\r\n");
44957 + con->response.content_length += b->used - 1;
44959 + chunkqueue_append_file(con->send, con->physical.path, r->start, r->end - r->start + 1);
44960 + con->response.content_length += r->end - r->start + 1;
44963 + /* add boundary end */
44964 + b = chunkqueue_get_append_buffer(con->send);
44966 buffer_copy_string_len(b, "\r\n--", 4);
44967 buffer_append_string(b, boundary);
44968 buffer_append_string_len(b, "--\r\n", 4);
44971 con->response.content_length += b->used - 1;
44974 /* set header-fields */
44977 buffer_copy_string(p->range_buf, "multipart/byteranges; boundary=");
44978 buffer_append_string(p->range_buf, boundary);
44981 /* overwrite content-type */
44982 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->range_buf));
44985 - /* add Content-Range-header */
44989 + chunkqueue_append_file(con->send, con->physical.path, r->start, r->end - r->start + 1);
44990 + con->response.content_length += r->end - r->start + 1;
44992 buffer_copy_string(p->range_buf, "bytes ");
44993 - buffer_append_off_t(p->range_buf, start);
44994 + buffer_append_off_t(p->range_buf, r->start);
44995 buffer_append_string(p->range_buf, "-");
44996 - buffer_append_off_t(p->range_buf, end);
44997 + buffer_append_off_t(p->range_buf, r->end);
44998 buffer_append_string(p->range_buf, "/");
44999 buffer_append_off_t(p->range_buf, sce->st.st_size);
45002 response_header_insert(srv, con, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(p->range_buf));
45006 /* ok, the file is set-up */
45009 @@ -347,12 +309,12 @@
45010 stat_cache_entry *sce = NULL;
45015 /* someone else has done a decision for us */
45016 if (con->http_status != 0) return HANDLER_GO_ON;
45017 if (con->uri.path->used == 0) return HANDLER_GO_ON;
45018 if (con->physical.path->used == 0) return HANDLER_GO_ON;
45021 /* someone else has handled this request */
45022 if (con->mode != DIRECT) return HANDLER_GO_ON;
45024 @@ -365,52 +327,67 @@
45026 return HANDLER_GO_ON;
45030 mod_staticfile_patch_connection(srv, con, p);
45033 s_len = con->uri.path->used - 1;
45036 /* ignore certain extensions */
45037 for (k = 0; k < p->conf.exclude_ext->used; k++) {
45038 - ds = (data_string *)p->conf.exclude_ext->data[k];
45040 + ds = (data_string *)p->conf.exclude_ext->data[k];
45042 if (ds->value->used == 0) continue;
45044 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
45045 - return HANDLER_GO_ON;
45046 + con->http_status = 403;
45048 + return HANDLER_FINISHED;
45054 if (con->conf.log_request_handling) {
45055 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling file as static file");
45059 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
45060 con->http_status = 403;
45063 log_error_write(srv, __FILE__, __LINE__, "sbsb",
45064 "not a regular file:", con->uri.path,
45065 "->", con->physical.path);
45068 return HANDLER_FINISHED;
45071 - /* we only handline regular files */
45073 + /* we only handle regular files */
45075 + if ((sce->is_symlink == 1) && !con->conf.follow_symlink) {
45076 + con->http_status = 403;
45078 + if (con->conf.log_request_handling) {
45079 + log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied due symlink restriction");
45080 + log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
45083 + buffer_reset(con->physical.path);
45084 + return HANDLER_FINISHED;
45087 if (!S_ISREG(sce->st.st_mode)) {
45088 con->http_status = 404;
45091 if (con->conf.log_file_not_found) {
45092 log_error_write(srv, __FILE__, __LINE__, "sbsb",
45093 "not a regular file:", con->uri.path,
45098 return HANDLER_FINISHED;
45101 - /* mod_compress might set several data directly, don't overwrite them */
45103 + /* mod_compress might set several parameters directly; don't overwrite them */
45105 /* set response content-type, if not set already */
45107 if (NULL == array_get_element(con->response.headers, "Content-Type")) {
45108 @@ -420,15 +397,15 @@
45109 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
45114 if (NULL == array_get_element(con->response.headers, "ETag")) {
45115 /* generate e-tag */
45116 etag_mutate(con->physical.etag, sce->etag);
45119 response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
45121 response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes"));
45124 /* prepare header */
45125 if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
45126 mtime = strftime_cache_get(srv, sce->st.st_mtime);
45127 @@ -439,54 +416,104 @@
45129 if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
45130 return HANDLER_FINISHED;
45131 - } else if (con->request.http_range && con->conf.range_requests) {
45132 + } else if (con->conf.range_requests &&
45133 + NULL != array_get_element(con->request.headers, "Range")) {
45134 int do_range_request = 1;
45135 /* check if we have a conditional GET */
45137 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If-Range"))) {
45138 - /* if the value is the same as our ETag, we do a Range-request,
45139 + /* if the value is the same as our ETag, we do a Range-request,
45140 * otherwise a full 200 */
45142 if (!buffer_is_equal(ds->value, con->physical.etag)) {
45143 do_range_request = 0;
45148 if (do_range_request) {
45149 /* content prepared, I'm done */
45150 - con->file_finished = 1;
45152 + con->send->is_closed = 1;
45154 if (0 == http_response_parse_range(srv, con, p)) {
45155 con->http_status = 206;
45157 return HANDLER_FINISHED;
45162 /* if we are still here, prepare body */
45164 - /* we add it here for all requests
45165 - * the HEAD request will drop it afterwards again
45167 + /* we add it here for all requests
45168 + * the HEAD request will drop it afterwards again
45170 - http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
45172 - con->file_finished = 1;
45174 + chunkqueue_append_file(con->send, con->physical.path, 0, sce->st.st_size);
45176 + con->send->is_closed = 1;
45178 return HANDLER_FINISHED;
45182 + * mark all the content as read
45184 +CONNECTION_FUNC(mod_staticfile_dev_null) {
45187 + chunkqueue *in = con->recv;
45189 + /* there is nothing that we have to send out anymore */
45190 + if (in->bytes_in == in->bytes_out &&
45191 + in->is_closed) return HANDLER_GO_ON;
45193 + for (c = in->first; in->bytes_out < in->bytes_in; c = c->next) {
45194 + off_t weWant = in->bytes_in - in->bytes_out;
45195 + off_t weHave = 0;
45197 + /* we announce toWrite octects
45198 + * now take all the request_content chunk that we need to fill this request
45201 + switch (c->type) {
45203 + weHave = c->file.length - c->offset;
45205 + if (weHave > weWant) weHave = weWant;
45207 + c->offset += weHave;
45208 + in->bytes_out += weHave;
45212 + /* append to the buffer */
45213 + weHave = c->mem->used - 1 - c->offset;
45215 + if (weHave > weWant) weHave = weWant;
45217 + c->offset += weHave;
45218 + in->bytes_out += weHave;
45226 + return HANDLER_GO_ON;
45229 /* this function is called at dlopen() time and inits the callbacks */
45231 int mod_staticfile_plugin_init(plugin *p) {
45232 p->version = LIGHTTPD_VERSION_ID;
45233 p->name = buffer_init_string("staticfile");
45236 p->init = mod_staticfile_init;
45237 - p->handle_subrequest_start = mod_staticfile_subrequest;
45238 + p->handle_start_backend = mod_staticfile_subrequest;
45239 + p->handle_send_request_content = mod_staticfile_dev_null;
45240 p->set_defaults = mod_staticfile_set_defaults;
45241 p->cleanup = mod_staticfile_free;
45249 --- ../lighttpd-1.4.11/src/mod_status.c 2006-01-10 21:45:32.000000000 +0200
45250 +++ lighttpd-1.5.0/src/mod_status.c 2006-09-07 00:57:05.000000000 +0300
45253 #include <stdlib.h>
45254 #include <string.h>
45255 -#include <unistd.h>
45260 #include "response.h"
45261 #include "connections.h"
45263 +#include "status_counter.h"
45265 #include "plugin.h"
45267 @@ -29,114 +29,114 @@
45273 double traffic_out;
45277 double mod_5s_traffic_out[5];
45278 double mod_5s_requests[5];
45282 double rel_traffic_out;
45283 double rel_requests;
45286 double abs_traffic_out;
45287 double abs_requests;
45290 double bytes_written;
45293 buffer *module_list;
45296 plugin_config **config_storage;
45298 - plugin_config conf;
45300 + plugin_config conf;
45303 INIT_FUNC(mod_status_init) {
45308 p = calloc(1, sizeof(*p));
45311 p->traffic_out = p->requests = 0;
45312 p->rel_traffic_out = p->rel_requests = 0;
45313 p->abs_traffic_out = p->abs_requests = 0;
45314 p->bytes_written = 0;
45315 p->module_list = buffer_init();
45318 for (i = 0; i < 5; i++) {
45319 p->mod_5s_traffic_out[i] = p->mod_5s_requests[i] = 0;
45326 FREE_FUNC(mod_status_free) {
45327 plugin_data *p = p_d;
45332 if (!p) return HANDLER_GO_ON;
45335 buffer_free(p->module_list);
45338 if (p->config_storage) {
45340 for (i = 0; i < srv->config_context->used; i++) {
45341 plugin_config *s = p->config_storage[i];
45344 buffer_free(s->status_url);
45345 buffer_free(s->statistics_url);
45346 buffer_free(s->config_url);
45351 free(p->config_storage);
45360 return HANDLER_GO_ON;
45363 SETDEFAULTS_FUNC(mod_status_set_defaults) {
45364 plugin_data *p = p_d;
45367 - config_values_t cv[] = {
45369 + config_values_t cv[] = {
45370 { "status.status-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
45371 { "status.config-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
45372 { "status.enable-sort", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
45373 { "status.statistics-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
45374 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
45378 if (!p) return HANDLER_ERROR;
45381 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
45384 for (i = 0; i < srv->config_context->used; i++) {
45388 s = calloc(1, sizeof(plugin_config));
45389 s->config_url = buffer_init();
45390 s->status_url = buffer_init();
45392 s->statistics_url = buffer_init();
45395 cv[0].destination = s->status_url;
45396 cv[1].destination = s->config_url;
45397 cv[2].destination = &(s->sort);
45398 cv[3].destination = s->statistics_url;
45401 p->config_storage[i] = s;
45404 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
45405 return HANDLER_ERROR;
45410 return HANDLER_GO_ON;
45413 @@ -151,7 +151,7 @@
45414 buffer_append_string(b, value);
45415 BUFFER_APPEND_STRING_CONST(b, "</td>\n");
45416 BUFFER_APPEND_STRING_CONST(b, " </tr>\n");
45422 @@ -161,13 +161,13 @@
45423 buffer_append_string(b, key);
45424 BUFFER_APPEND_STRING_CONST(b, "</th>\n");
45425 BUFFER_APPEND_STRING_CONST(b, " </tr>\n");
45431 static int mod_status_header_append_sort(buffer *b, void *p_d, const char* key) {
45432 plugin_data *p = p_d;
45435 if (p->conf.sort) {
45436 BUFFER_APPEND_STRING_CONST(b, "<th class=\"status\"><a href=\"#\" class=\"sortheader\" onclick=\"resort(this);return false;\">");
45437 buffer_append_string(b, key);
45438 @@ -177,13 +177,13 @@
45439 buffer_append_string(b, key);
45440 BUFFER_APPEND_STRING_CONST(b, "</th>\n");
45447 static int mod_status_get_multiplier(double *avg, char *multiplier, int size) {
45451 if (*avg > size) { *avg /= size; *multiplier = 'k'; }
45452 if (*avg > size) { *avg /= size; *multiplier = 'M'; }
45453 if (*avg > size) { *avg /= size; *multiplier = 'G'; }
45454 @@ -202,21 +202,21 @@
45457 char multiplier = '\0';
45463 int days, hours, mins, seconds;
45465 - b = chunkqueue_get_append_buffer(con->write_queue);
45467 - BUFFER_COPY_STRING_CONST(b,
45468 + b = chunkqueue_get_append_buffer(con->send);
45470 + BUFFER_COPY_STRING_CONST(b,
45471 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
45472 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
45473 " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
45474 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
45476 " <title>Status</title>\n");
45479 BUFFER_APPEND_STRING_CONST(b,
45480 " <style type=\"text/css\">\n"
45481 " table.status { border: black solid thin; }\n"
45482 @@ -226,14 +226,14 @@
45483 " a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n"
45484 " span.sortarrow { color: white; text-decoration: none; }\n"
45488 if (p->conf.sort) {
45489 BUFFER_APPEND_STRING_CONST(b,
45490 "<script type=\"text/javascript\">\n"
45492 "var sort_column;\n"
45493 "var prev_span = null;\n");
45496 BUFFER_APPEND_STRING_CONST(b,
45497 "function get_inner_text(el) {\n"
45498 " if((typeof el == 'string')||(typeof el == 'undefined'))\n"
45499 @@ -251,7 +251,7 @@
45505 BUFFER_APPEND_STRING_CONST(b,
45506 "function sortfn(a,b) {\n"
45507 " var at = get_inner_text(a.cells[sort_column]);\n"
45508 @@ -266,7 +266,7 @@
45509 " else return 1;\n"
45514 BUFFER_APPEND_STRING_CONST(b,
45515 "function resort(lnk) {\n"
45516 " var span = lnk.childNodes[1];\n"
45517 @@ -276,7 +276,7 @@
45518 " rows[j-1] = table.rows[j];\n"
45519 " sort_column = lnk.parentNode.cellIndex;\n"
45520 " rows.sort(sortfn);\n");
45523 BUFFER_APPEND_STRING_CONST(b,
45524 " if (prev_span != null) prev_span.innerHTML = '';\n"
45525 " if (span.getAttribute('sortdir')=='down') {\n"
45526 @@ -294,175 +294,175 @@
45531 - BUFFER_APPEND_STRING_CONST(b,
45533 + BUFFER_APPEND_STRING_CONST(b,
45542 /* connection listing */
45543 BUFFER_APPEND_STRING_CONST(b, "<h1>Server-Status</h1>");
45545 - BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">");
45546 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\">");
45548 + BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" id=\"status\" summary=\"Server Status\">");
45549 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\"><span id=\"host_addr\">");
45550 buffer_append_string_buffer(b, con->uri.authority);
45551 - BUFFER_APPEND_STRING_CONST(b, " (");
45552 + BUFFER_APPEND_STRING_CONST(b, "</span> (<span id=\"host_name\">");
45553 buffer_append_string_buffer(b, con->server_name);
45554 - BUFFER_APPEND_STRING_CONST(b, ")</td></tr>\n");
45555 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\">");
45557 + BUFFER_APPEND_STRING_CONST(b, "</span>)</td></tr>\n");
45558 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\" id=\"uptime\">");
45560 ts = srv->cur_ts - srv->startup_ts;
45563 days = ts / (60 * 60 * 24);
45564 ts %= (60 * 60 * 24);
45567 hours = ts / (60 * 60);
45579 buffer_append_long(b, days);
45580 BUFFER_APPEND_STRING_CONST(b, " days ");
45585 buffer_append_long(b, hours);
45586 BUFFER_APPEND_STRING_CONST(b, " hours ");
45591 buffer_append_long(b, mins);
45592 BUFFER_APPEND_STRING_CONST(b, " min ");
45596 buffer_append_long(b, seconds);
45597 BUFFER_APPEND_STRING_CONST(b, " s");
45600 BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
45601 BUFFER_APPEND_STRING_CONST(b, "<tr><td>Started at</td><td class=\"string\">");
45604 ts = srv->startup_ts;
45606 - strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts));
45608 + strftime(buf, sizeof(buf) - 1, "<span id=\"start_date\">%Y-%m-%d</span> <span id=\"start_time\">%H:%M:%S</span>", localtime(&ts));
45609 buffer_append_string(b, buf);
45610 BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
45615 BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">absolute (since start)</th></tr>\n");
45617 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
45619 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\" ><span id=\"requests\">");
45620 avg = p->abs_requests;
45622 mod_status_get_multiplier(&avg, &multiplier, 1000);
45625 buffer_append_long(b, avg);
45626 - BUFFER_APPEND_STRING_CONST(b, " ");
45627 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_mult\">");
45628 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
45629 - BUFFER_APPEND_STRING_CONST(b, "req</td></tr>\n");
45631 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
45632 + BUFFER_APPEND_STRING_CONST(b, "</span>req</td></tr>\n");
45634 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic\">");
45635 avg = p->abs_traffic_out;
45637 mod_status_get_multiplier(&avg, &multiplier, 1024);
45639 sprintf(buf, "%.2f", avg);
45640 buffer_append_string(b, buf);
45641 - BUFFER_APPEND_STRING_CONST(b, " ");
45642 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"traffic_mult\">");
45643 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
45644 - BUFFER_APPEND_STRING_CONST(b, "byte</td></tr>\n");
45645 + BUFFER_APPEND_STRING_CONST(b, "</span>byte</td></tr>\n");
45649 BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (since start)</th></tr>\n");
45651 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
45653 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_avg\">");
45654 avg = p->abs_requests / (srv->cur_ts - srv->startup_ts);
45656 mod_status_get_multiplier(&avg, &multiplier, 1000);
45658 buffer_append_long(b, avg);
45659 - BUFFER_APPEND_STRING_CONST(b, " ");
45660 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_avg_mult\">");
45661 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
45662 - BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
45664 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
45665 + BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
45667 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic_avg\">");
45668 avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts);
45670 mod_status_get_multiplier(&avg, &multiplier, 1024);
45672 sprintf(buf, "%.2f", avg);
45673 buffer_append_string(b, buf);
45674 - BUFFER_APPEND_STRING_CONST(b, " ");
45675 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"traffic_avg_mult\">");
45676 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
45677 - BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
45678 + BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
45684 BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n");
45685 for (j = 0, avg = 0; j < 5; j++) {
45686 avg += p->mod_5s_requests[j];
45692 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
45694 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_sliding_avg\">");
45696 mod_status_get_multiplier(&avg, &multiplier, 1000);
45698 buffer_append_long(b, avg);
45699 - BUFFER_APPEND_STRING_CONST(b, " ");
45700 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_avg_mult\">");
45701 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
45703 - BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
45706 + BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
45708 for (j = 0, avg = 0; j < 5; j++) {
45709 avg += p->mod_5s_traffic_out[j];
45715 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
45717 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"requests_sliding_traffic\">");
45719 mod_status_get_multiplier(&avg, &multiplier, 1024);
45721 sprintf(buf, "%.2f", avg);
45722 buffer_append_string(b, buf);
45723 - BUFFER_APPEND_STRING_CONST(b, " ");
45724 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_traffic_mult\">");
45725 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
45726 - BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
45728 + BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
45730 BUFFER_APPEND_STRING_CONST(b, "</table>\n");
45735 BUFFER_APPEND_STRING_CONST(b, "<hr />\n<pre><b>legend</b>\n");
45736 BUFFER_APPEND_STRING_CONST(b, ". = connect, C = close, E = hard error\n");
45737 BUFFER_APPEND_STRING_CONST(b, "r = read, R = read-POST, W = write, h = handle-request\n");
45738 BUFFER_APPEND_STRING_CONST(b, "q = request-start, Q = request-end\n");
45739 BUFFER_APPEND_STRING_CONST(b, "s = response-start, S = response-end\n");
45741 - BUFFER_APPEND_STRING_CONST(b, "<b>");
45743 + BUFFER_APPEND_STRING_CONST(b, "<strong><span id=\"connections\">");
45744 buffer_append_long(b, srv->conns->used);
45745 - BUFFER_APPEND_STRING_CONST(b, " connections</b>\n");
45747 + BUFFER_APPEND_STRING_CONST(b, "</span> connections</strong>\n");
45749 for (j = 0; j < srv->conns->used; j++) {
45750 connection *c = srv->conns->ptr[j];
45751 const char *state = connection_get_short_state(c->state);
45754 buffer_append_string_len(b, state, 1);
45757 if (((j + 1) % 50) == 0) {
45758 BUFFER_APPEND_STRING_CONST(b, "\n");
45763 BUFFER_APPEND_STRING_CONST(b, "\n</pre><hr />\n<h2>Connections</h2>\n");
45765 - BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">\n");
45767 + BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" summary=\"Current connections\" id=\"clients\">\n");
45768 BUFFER_APPEND_STRING_CONST(b, "<tr>");
45769 mod_status_header_append_sort(b, p_d, "Client IP");
45770 mod_status_header_append_sort(b, p_d, "Read");
45771 @@ -473,72 +473,72 @@
45772 mod_status_header_append_sort(b, p_d, "URI");
45773 mod_status_header_append_sort(b, p_d, "File");
45774 BUFFER_APPEND_STRING_CONST(b, "</tr>\n");
45777 for (j = 0; j < srv->conns->used; j++) {
45778 connection *c = srv->conns->ptr[j];
45780 - BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string\">");
45783 + BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string ip\">");
45785 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr)));
45787 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
45789 - if (con->request.content_length) {
45790 - buffer_append_long(b, c->request_content_queue->bytes_in);
45792 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_read\">");
45794 + if (c->request.content_length != -1) {
45795 + buffer_append_long(b, c->recv->bytes_in);
45796 BUFFER_APPEND_STRING_CONST(b, "/");
45797 buffer_append_long(b, c->request.content_length);
45799 BUFFER_APPEND_STRING_CONST(b, "0/0");
45802 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
45804 - buffer_append_off_t(b, chunkqueue_written(c->write_queue));
45806 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_written\">");
45808 + buffer_append_off_t(b, chunkqueue_written(c->send_raw));
45809 BUFFER_APPEND_STRING_CONST(b, "/");
45810 - buffer_append_off_t(b, chunkqueue_length(c->write_queue));
45812 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
45814 + buffer_append_off_t(b, chunkqueue_length(c->send_raw));
45816 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string state\">");
45818 buffer_append_string(b, connection_get_state(c->state));
45820 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
45823 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int time\">");
45825 buffer_append_long(b, srv->cur_ts - c->request_start);
45827 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
45830 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string host\">");
45832 if (buffer_is_empty(c->server_name)) {
45833 buffer_append_string_buffer(b, c->uri.authority);
45836 buffer_append_string_buffer(b, c->server_name);
45839 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
45842 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string uri\">");
45844 if (!buffer_is_empty(c->uri.path)) {
45845 buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML);
45848 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
45851 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string file\">");
45853 buffer_append_string_buffer(b, c->physical.path);
45856 BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
45860 - BUFFER_APPEND_STRING_CONST(b,
45863 + BUFFER_APPEND_STRING_CONST(b,
45867 - BUFFER_APPEND_STRING_CONST(b,
45870 + BUFFER_APPEND_STRING_CONST(b,
45876 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
45882 @@ -548,27 +548,27 @@
45887 - b = chunkqueue_get_append_buffer(con->write_queue);
45889 + b = chunkqueue_get_append_buffer(con->send);
45891 /* output total number of requests */
45892 BUFFER_APPEND_STRING_CONST(b, "Total Accesses: ");
45893 avg = p->abs_requests;
45894 buffer_append_long(b, avg);
45895 BUFFER_APPEND_STRING_CONST(b, "\n");
45898 /* output total traffic out in kbytes */
45899 BUFFER_APPEND_STRING_CONST(b, "Total kBytes: ");
45900 avg = p->abs_traffic_out / 1024;
45901 buffer_append_long(b, avg);
45902 BUFFER_APPEND_STRING_CONST(b, "\n");
45905 /* output uptime */
45906 BUFFER_APPEND_STRING_CONST(b, "Uptime: ");
45907 ts = srv->cur_ts - srv->startup_ts;
45908 buffer_append_long(b, ts);
45909 BUFFER_APPEND_STRING_CONST(b, "\n");
45912 /* output busy servers */
45913 BUFFER_APPEND_STRING_CONST(b, "BusyServers: ");
45914 buffer_append_long(b, srv->conns->used);
45915 @@ -577,7 +577,7 @@
45916 /* set text/plain output */
45918 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
45924 @@ -585,17 +585,17 @@
45925 plugin_data *p = p_d;
45926 buffer *b, *m = p->module_list;
45928 - array *st = srv->status;
45929 + array *st = status_counter_get_array();
45931 if (0 == st->used) {
45932 /* we have nothing to send */
45933 con->http_status = 204;
45934 - con->file_finished = 1;
45936 + con->send->is_closed = 1;
45938 return HANDLER_FINISHED;
45941 - b = chunkqueue_get_append_buffer(con->write_queue);
45943 + b = chunkqueue_get_append_buffer(con->send);
45945 for (i = 0; i < st->used; i++) {
45946 size_t ndx = st->sorted[i];
45947 @@ -605,27 +605,27 @@
45948 buffer_append_long(b, ((data_integer *)(st->data[ndx]))->value);
45949 buffer_append_string(b, "\n");
45953 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
45956 con->http_status = 200;
45957 - con->file_finished = 1;
45959 + con->send->is_closed = 1;
45961 return HANDLER_FINISHED;
45965 static handler_t mod_status_handle_server_status(server *srv, connection *con, void *p_d) {
45968 if (buffer_is_equal_string(con->uri.query, CONST_STR_LEN("auto"))) {
45969 mod_status_handle_server_status_text(srv, con, p_d);
45971 mod_status_handle_server_status_html(srv, con, p_d);
45975 con->http_status = 200;
45976 - con->file_finished = 1;
45978 + con->send->is_closed = 1;
45980 return HANDLER_FINISHED;
45983 @@ -634,9 +634,9 @@
45984 plugin_data *p = p_d;
45985 buffer *b, *m = p->module_list;
45988 - struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
45991 + struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
45993 /* - poll is most reliable
45994 * - select works everywhere
45995 * - linux-* are experimental
45996 @@ -661,10 +661,10 @@
45998 { FDEVENT_HANDLER_UNSET, NULL }
46001 - b = chunkqueue_get_append_buffer(con->write_queue);
46003 - BUFFER_COPY_STRING_CONST(b,
46005 + b = chunkqueue_get_append_buffer(con->send);
46007 + BUFFER_COPY_STRING_CONST(b,
46008 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
46009 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
46010 " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
46011 @@ -675,7 +675,7 @@
46013 " <h1>" PACKAGE_NAME " " PACKAGE_VERSION "</h1>\n"
46014 " <table border=\"1\">\n");
46017 mod_status_header_append(b, "Server-Features");
46019 mod_status_row_append(b, "RegEx Conditionals", "enabled");
46020 @@ -683,21 +683,21 @@
46021 mod_status_row_append(b, "RegEx Conditionals", "disabled - pcre missing");
46023 mod_status_header_append(b, "Network Engine");
46026 for (i = 0; event_handlers[i].name; i++) {
46027 if (event_handlers[i].et == srv->event_handler) {
46028 mod_status_row_append(b, "fd-Event-Handler", event_handlers[i].name);
46034 mod_status_header_append(b, "Config-File-Settings");
46037 for (i = 0; i < srv->plugins.used; i++) {
46038 plugin **ps = srv->plugins.ptr;
46041 plugin *pl = ps[i];
46045 buffer_copy_string_buffer(m, pl->name);
46047 @@ -705,137 +705,135 @@
46048 buffer_append_string_buffer(m, pl->name);
46053 mod_status_row_append(b, "Loaded Modules", m->ptr);
46056 BUFFER_APPEND_STRING_CONST(b, " </table>\n");
46058 - BUFFER_APPEND_STRING_CONST(b,
46060 + BUFFER_APPEND_STRING_CONST(b,
46066 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
46069 con->http_status = 200;
46070 - con->file_finished = 1;
46072 + con->send->is_closed = 1;
46074 return HANDLER_FINISHED;
46077 -#define PATCH(x) \
46078 - p->conf.x = s->x;
46079 static int mod_status_patch_connection(server *srv, connection *con, plugin_data *p) {
46081 plugin_config *s = p->config_storage[0];
46083 - PATCH(status_url);
46084 - PATCH(config_url);
46086 - PATCH(statistics_url);
46089 + PATCH_OPTION(status_url);
46090 + PATCH_OPTION(config_url);
46091 + PATCH_OPTION(sort);
46092 + PATCH_OPTION(statistics_url);
46094 /* skip the first, the global context */
46095 for (i = 1; i < srv->config_context->used; i++) {
46096 data_config *dc = (data_config *)srv->config_context->data[i];
46097 s = p->config_storage[i];
46100 /* condition didn't match */
46101 if (!config_check_cond(srv, con, dc)) continue;
46105 for (j = 0; j < dc->value->used; j++) {
46106 data_unset *du = dc->value->data[j];
46109 if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.status-url"))) {
46110 - PATCH(status_url);
46111 + PATCH_OPTION(status_url);
46112 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.config-url"))) {
46113 - PATCH(config_url);
46114 + PATCH_OPTION(config_url);
46115 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.enable-sort"))) {
46117 + PATCH_OPTION(sort);
46118 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.statistics-url"))) {
46119 - PATCH(statistics_url);
46121 + PATCH_OPTION(statistics_url);
46130 static handler_t mod_status_handler(server *srv, connection *con, void *p_d) {
46131 plugin_data *p = p_d;
46134 mod_status_patch_connection(srv, con, p);
46136 - if (!buffer_is_empty(p->conf.status_url) &&
46138 + if (!buffer_is_empty(p->conf.status_url) &&
46139 buffer_is_equal(p->conf.status_url, con->uri.path)) {
46140 return mod_status_handle_server_status(srv, con, p_d);
46141 - } else if (!buffer_is_empty(p->conf.config_url) &&
46142 + } else if (!buffer_is_empty(p->conf.config_url) &&
46143 buffer_is_equal(p->conf.config_url, con->uri.path)) {
46144 return mod_status_handle_server_config(srv, con, p_d);
46145 - } else if (!buffer_is_empty(p->conf.statistics_url) &&
46146 + } else if (!buffer_is_empty(p->conf.statistics_url) &&
46147 buffer_is_equal(p->conf.statistics_url, con->uri.path)) {
46148 return mod_status_handle_server_statistics(srv, con, p_d);
46152 return HANDLER_GO_ON;
46155 TRIGGER_FUNC(mod_status_trigger) {
46156 plugin_data *p = p_d;
46160 /* check all connections */
46161 for (i = 0; i < srv->conns->used; i++) {
46162 connection *c = srv->conns->ptr[i];
46165 p->bytes_written += c->bytes_written_cur_second;
46169 /* a sliding average */
46170 p->mod_5s_traffic_out[p->mod_5s_ndx] = p->bytes_written;
46171 p->mod_5s_requests [p->mod_5s_ndx] = p->requests;
46174 p->mod_5s_ndx = (p->mod_5s_ndx+1) % 5;
46177 p->abs_traffic_out += p->bytes_written;
46178 p->rel_traffic_out += p->bytes_written;
46181 p->bytes_written = 0;
46184 /* reset storage - second */
46185 p->traffic_out = 0;
46189 return HANDLER_GO_ON;
46192 REQUESTDONE_FUNC(mod_status_account) {
46193 plugin_data *p = p_d;
46203 p->bytes_written += con->bytes_written_cur_second;
46206 return HANDLER_GO_ON;
46209 int mod_status_plugin_init(plugin *p) {
46210 p->version = LIGHTTPD_VERSION_ID;
46211 p->name = buffer_init_string("status");
46214 p->init = mod_status_init;
46215 p->cleanup = mod_status_free;
46216 p->set_defaults= mod_status_set_defaults;
46219 p->handle_uri_clean = mod_status_handler;
46220 p->handle_trigger = mod_status_trigger;
46221 - p->handle_request_done = mod_status_account;
46223 + p->handle_response_done = mod_status_account;
46230 --- ../lighttpd-1.4.11/src/mod_trigger_b4_dl.c 2005-09-23 22:53:55.000000000 +0300
46231 +++ lighttpd-1.5.0/src/mod_trigger_b4_dl.c 2006-07-16 00:26:03.000000000 +0300
46232 @@ -24,18 +24,18 @@
46235 * this is a trigger_b4_dl for a lighttpd plugin
46240 /* plugin config for all request/connections */
46243 buffer *db_filename;
46246 buffer *trigger_url;
46247 buffer *download_url;
46252 buffer *mc_namespace;
46253 #if defined(HAVE_PCRE_H)
46254 @@ -46,58 +46,58 @@
46258 -#if defined(HAVE_MEMCACHE_H)
46259 +#if defined(HAVE_MEMCACHE_H)
46260 struct memcache *mc;
46264 unsigned short trigger_timeout;
46265 unsigned short debug;
46275 plugin_config **config_storage;
46277 - plugin_config conf;
46279 + plugin_config conf;
46282 /* init the plugin data */
46283 INIT_FUNC(mod_trigger_b4_dl_init) {
46287 p = calloc(1, sizeof(*p));
46290 p->tmp_buf = buffer_init();
46296 /* detroy the plugin data */
46297 FREE_FUNC(mod_trigger_b4_dl_free) {
46298 plugin_data *p = p_d;
46303 if (!p) return HANDLER_GO_ON;
46306 if (p->config_storage) {
46308 for (i = 0; i < srv->config_context->used; i++) {
46309 plugin_config *s = p->config_storage[i];
46314 buffer_free(s->db_filename);
46315 buffer_free(s->download_url);
46316 buffer_free(s->trigger_url);
46317 buffer_free(s->deny_url);
46320 buffer_free(s->mc_namespace);
46321 array_free(s->mc_hosts);
46324 #if defined(HAVE_PCRE_H)
46325 if (s->trigger_regex) pcre_free(s->trigger_regex);
46326 if (s->download_regex) pcre_free(s->download_regex);
46327 @@ -108,16 +108,16 @@
46328 #if defined(HAVE_MEMCACHE_H)
46329 if (s->mc) mc_free(s->mc);
46335 free(p->config_storage);
46339 buffer_free(p->tmp_buf);
46345 return HANDLER_GO_ON;
46348 @@ -126,9 +126,9 @@
46349 SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
46350 plugin_data *p = p_d;
46354 - config_values_t cv[] = {
46357 + config_values_t cv[] = {
46358 { "trigger-before-download.gdbm-filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
46359 { "trigger-before-download.trigger-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
46360 { "trigger-before-download.download-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
46361 @@ -139,18 +139,18 @@
46362 { "trigger-before-download.debug", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
46363 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
46367 if (!p) return HANDLER_ERROR;
46370 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
46373 for (i = 0; i < srv->config_context->used; i++) {
46375 #if defined(HAVE_PCRE_H)
46376 const char *errptr;
46381 s = calloc(1, sizeof(plugin_config));
46382 s->db_filename = buffer_init();
46383 s->download_url = buffer_init();
46384 @@ -158,7 +158,7 @@
46385 s->deny_url = buffer_init();
46386 s->mc_hosts = array_init();
46387 s->mc_namespace = buffer_init();
46390 cv[0].destination = s->db_filename;
46391 cv[1].destination = s->trigger_url;
46392 cv[2].destination = s->download_url;
46393 @@ -167,41 +167,41 @@
46394 cv[5].destination = s->mc_hosts;
46395 cv[6].destination = s->mc_namespace;
46396 cv[7].destination = &(s->debug);
46399 p->config_storage[i] = s;
46402 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
46403 return HANDLER_ERROR;
46405 #if defined(HAVE_GDBM_H)
46406 if (!buffer_is_empty(s->db_filename)) {
46407 if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) {
46408 - log_error_write(srv, __FILE__, __LINE__, "s",
46409 + log_error_write(srv, __FILE__, __LINE__, "s",
46410 "gdbm-open failed");
46411 return HANDLER_ERROR;
46415 -#if defined(HAVE_PCRE_H)
46416 +#if defined(HAVE_PCRE_H)
46417 if (!buffer_is_empty(s->download_url)) {
46418 if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr,
46419 0, &errptr, &erroff, NULL))) {
46421 - log_error_write(srv, __FILE__, __LINE__, "sbss",
46422 - "compiling regex for download-url failed:",
46424 + log_error_write(srv, __FILE__, __LINE__, "sbss",
46425 + "compiling regex for download-url failed:",
46426 s->download_url, "pos:", erroff);
46427 return HANDLER_ERROR;
46432 if (!buffer_is_empty(s->trigger_url)) {
46433 if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr,
46434 0, &errptr, &erroff, NULL))) {
46436 - log_error_write(srv, __FILE__, __LINE__, "sbss",
46437 - "compiling regex for trigger-url failed:",
46439 + log_error_write(srv, __FILE__, __LINE__, "sbss",
46440 + "compiling regex for trigger-url failed:",
46441 s->trigger_url, "pos:", erroff);
46444 return HANDLER_ERROR;
46447 @@ -211,100 +211,97 @@
46448 #if defined(HAVE_MEMCACHE_H)
46453 for (k = 0; k < s->mc_hosts->used; k++) {
46454 data_string *ds = (data_string *)s->mc_hosts->data[k];
46457 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
46458 - log_error_write(srv, __FILE__, __LINE__, "sb",
46459 - "connection to host failed:",
46460 + log_error_write(srv, __FILE__, __LINE__, "sb",
46461 + "connection to host failed:",
46465 return HANDLER_ERROR;
46469 - log_error_write(srv, __FILE__, __LINE__, "s",
46470 + log_error_write(srv, __FILE__, __LINE__, "s",
46471 "memcache support is not compiled in but trigger-before-download.memcache-hosts is set, aborting");
46472 return HANDLER_ERROR;
46478 #if (!defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)) || !defined(HAVE_PCRE_H)
46479 - log_error_write(srv, __FILE__, __LINE__, "s",
46480 + log_error_write(srv, __FILE__, __LINE__, "s",
46481 "(either gdbm or libmemcache) and pcre are require, but were not found, aborting");
46482 return HANDLER_ERROR;
46487 return HANDLER_GO_ON;
46490 -#define PATCH(x) \
46491 - p->conf.x = s->x;
46492 static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plugin_data *p) {
46494 plugin_config *s = p->config_storage[0];
46497 #if defined(HAVE_GDBM)
46500 + PATCH_OPTION(db);
46502 #if defined(HAVE_PCRE_H)
46503 - PATCH(download_regex);
46504 - PATCH(trigger_regex);
46506 - PATCH(trigger_timeout);
46508 - PATCH(mc_namespace);
46510 + PATCH_OPTION(download_regex);
46511 + PATCH_OPTION(trigger_regex);
46513 + PATCH_OPTION(trigger_timeout);
46514 + PATCH_OPTION(deny_url);
46515 + PATCH_OPTION(mc_namespace);
46516 + PATCH_OPTION(debug);
46517 #if defined(HAVE_MEMCACHE_H)
46519 + PATCH_OPTION(mc);
46523 /* skip the first, the global context */
46524 for (i = 1; i < srv->config_context->used; i++) {
46525 data_config *dc = (data_config *)srv->config_context->data[i];
46526 s = p->config_storage[i];
46529 /* condition didn't match */
46530 if (!config_check_cond(srv, con, dc)) continue;
46534 for (j = 0; j < dc->value->used; j++) {
46535 data_unset *du = dc->value->data[j];
46537 if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.download-url"))) {
46538 #if defined(HAVE_PCRE_H)
46539 - PATCH(download_regex);
46540 + PATCH_OPTION(download_regex);
46542 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-url"))) {
46543 # if defined(HAVE_PCRE_H)
46544 - PATCH(trigger_regex);
46545 + PATCH_OPTION(trigger_regex);
46547 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.gdbm-filename"))) {
46548 #if defined(HAVE_GDBM_H)
46550 + PATCH_OPTION(db);
46552 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-timeout"))) {
46553 - PATCH(trigger_timeout);
46554 + PATCH_OPTION(trigger_timeout);
46555 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.debug"))) {
46557 + PATCH_OPTION(debug);
46558 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.deny-url"))) {
46560 + PATCH_OPTION(deny_url);
46561 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-namespace"))) {
46562 - PATCH(mc_namespace);
46563 + PATCH_OPTION(mc_namespace);
46564 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-hosts"))) {
46565 #if defined(HAVE_MEMCACHE_H)
46567 + PATCH_OPTION(mc);
46578 URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
46579 plugin_data *p = p_d;
46580 @@ -315,20 +312,20 @@
46586 if (con->uri.path->used == 0) return HANDLER_GO_ON;
46589 mod_trigger_b4_dl_patch_connection(srv, con, p);
46592 if (!p->conf.trigger_regex || !p->conf.download_regex) return HANDLER_GO_ON;
46595 # if !defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)
46596 return HANDLER_GO_ON;
46597 # elif defined(HAVE_GDBM_H) && defined(HAVE_MEMCACHE_H)
46598 if (!p->conf.db && !p->conf.mc) return HANDLER_GO_ON;
46599 if (p->conf.db && p->conf.mc) {
46600 /* can't decide which one */
46603 return HANDLER_GO_ON;
46605 # elif defined(HAVE_GDBM_H)
46606 @@ -336,12 +333,12 @@
46608 if (!p->conf.mc) return HANDLER_GO_ON;
46612 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "X-Forwarded-For"))) {
46613 /* X-Forwarded-For contains the ip behind the proxy */
46616 remote_ip = ds->value->ptr;
46619 /* memcache can't handle spaces */
46621 remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
46622 @@ -350,13 +347,13 @@
46623 if (p->conf.debug) {
46624 log_error_write(srv, __FILE__, __LINE__, "ss", "(debug) remote-ip:", remote_ip);
46628 /* check if URL is a trigger -> insert IP into DB */
46629 if ((n = pcre_exec(p->conf.trigger_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
46630 if (n != PCRE_ERROR_NOMATCH) {
46631 log_error_write(srv, __FILE__, __LINE__, "sd",
46632 "execution error while matching:", n);
46635 return HANDLER_ERROR;
46638 @@ -364,34 +361,34 @@
46640 /* the trigger matched */
46644 key.dptr = (char *)remote_ip;
46645 key.dsize = strlen(remote_ip);
46648 val.dptr = (char *)&(srv->cur_ts);
46649 val.dsize = sizeof(srv->cur_ts);
46652 if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
46653 log_error_write(srv, __FILE__, __LINE__, "s",
46658 -# if defined(HAVE_MEMCACHE_H)
46659 +# if defined(HAVE_MEMCACHE_H)
46662 buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
46663 buffer_append_string(p->tmp_buf, remote_ip);
46666 for (i = 0; i < p->tmp_buf->used - 1; i++) {
46667 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
46671 if (p->conf.debug) {
46672 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) triggered IP:", p->tmp_buf);
46675 - if (0 != mc_set(p->conf.mc,
46676 + if (0 != mc_set(p->conf.mc,
46677 CONST_BUF_LEN(p->tmp_buf),
46678 (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
46679 p->conf.trigger_timeout, 0)) {
46680 @@ -401,7 +398,7 @@
46686 /* check if URL is a download -> check IP in DB, update timestamp */
46687 if ((n = pcre_exec(p->conf.download_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
46688 if (n != PCRE_ERROR_NOMATCH) {
46689 @@ -411,93 +408,93 @@
46692 /* the download uri matched */
46693 -# if defined(HAVE_GDBM_H)
46694 +# if defined(HAVE_GDBM_H)
46700 key.dptr = (char *)remote_ip;
46701 key.dsize = strlen(remote_ip);
46704 val = gdbm_fetch(p->conf.db, key);
46707 if (val.dptr == NULL) {
46708 /* not found, redirect */
46711 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
46714 con->http_status = 307;
46717 return HANDLER_FINISHED;
46721 last_hit = *(time_t *)(val.dptr);
46727 if (srv->cur_ts - last_hit > p->conf.trigger_timeout) {
46728 /* found, but timeout, redirect */
46731 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
46732 con->http_status = 307;
46736 if (0 != gdbm_delete(p->conf.db, key)) {
46737 log_error_write(srv, __FILE__, __LINE__, "s",
46743 return HANDLER_FINISHED;
46747 val.dptr = (char *)&(srv->cur_ts);
46748 val.dsize = sizeof(srv->cur_ts);
46751 if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
46752 log_error_write(srv, __FILE__, __LINE__, "s",
46758 -# if defined(HAVE_MEMCACHE_H)
46760 +# if defined(HAVE_MEMCACHE_H)
46766 buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
46767 buffer_append_string(p->tmp_buf, remote_ip);
46770 for (i = 0; i < p->tmp_buf->used - 1; i++) {
46771 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
46775 if (p->conf.debug) {
46776 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) checking IP:", p->tmp_buf);
46782 * memcached is do expiration for us, as long as we can fetch it every thing is ok
46783 - * and the timestamp is updated
46785 + * and the timestamp is updated
46788 - if (NULL == (r = mc_aget(p->conf.mc,
46789 + if (NULL == (r = mc_aget(p->conf.mc,
46790 CONST_BUF_LEN(p->tmp_buf)
46794 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
46797 con->http_status = 307;
46800 return HANDLER_FINISHED;
46807 /* set a new timeout */
46808 - if (0 != mc_set(p->conf.mc,
46809 + if (0 != mc_set(p->conf.mc,
46810 CONST_BUF_LEN(p->tmp_buf),
46811 (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
46812 p->conf.trigger_timeout, 0)) {
46813 @@ -507,13 +504,13 @@
46826 return HANDLER_GO_ON;
46829 @@ -521,21 +518,21 @@
46830 TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
46831 plugin_data *p = p_d;
46835 /* check DB each minute */
46836 if (srv->cur_ts % 60 != 0) return HANDLER_GO_ON;
46840 for (i = 0; i < srv->config_context->used; i++) {
46841 plugin_config *s = p->config_storage[i];
46842 datum key, val, okey;
46845 if (!s->db) continue;
46850 - /* according to the manual this loop + delete does delete all entries on its way
46853 + /* according to the manual this loop + delete does delete all entries on its way
46855 * we don't care as the next round will remove them. We don't have to perfect here.
46857 for (key = gdbm_firstkey(s->db); key.dptr; key = gdbm_nextkey(s->db, okey)) {
46858 @@ -544,21 +541,21 @@
46864 val = gdbm_fetch(s->db, key);
46867 last_hit = *(time_t *)(val.dptr);
46873 if (srv->cur_ts - last_hit > s->trigger_timeout) {
46874 gdbm_delete(s->db, key);
46880 if (okey.dptr) free(okey.dptr);
46883 /* reorg once a day */
46884 if ((srv->cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(s->db);
46886 @@ -571,7 +568,7 @@
46887 int mod_trigger_b4_dl_plugin_init(plugin *p) {
46888 p->version = LIGHTTPD_VERSION_ID;
46889 p->name = buffer_init_string("trigger_b4_dl");
46892 p->init = mod_trigger_b4_dl_init;
46893 p->handle_uri_clean = mod_trigger_b4_dl_uri_handler;
46894 p->set_defaults = mod_trigger_b4_dl_set_defaults;
46895 @@ -579,8 +576,8 @@
46896 p->handle_trigger = mod_trigger_b4_dl_handle_trigger;
46898 p->cleanup = mod_trigger_b4_dl_free;
46906 --- ../lighttpd-1.4.11/src/mod_uploadprogress.c 1970-01-01 03:00:00.000000000 +0300
46907 +++ lighttpd-1.5.0/src/mod_uploadprogress.c 2006-09-07 00:57:05.000000000 +0300
46909 +#include <ctype.h>
46910 +#include <stdlib.h>
46911 +#include <string.h>
46915 +#include "buffer.h"
46917 +#include "plugin.h"
46919 +#include "response.h"
46920 +#include "stat_cache.h"
46923 + * this is a uploadprogress for a lighttpd plugin
46930 +} connection_map_entry;
46933 + connection_map_entry **ptr;
46939 +/* plugin config for all request/connections */
46942 + buffer *progress_url;
46948 + connection_map *con_map;
46950 + plugin_config **config_storage;
46952 + plugin_config conf;
46957 + * connection maps
46961 +/* init the plugin data */
46962 +connection_map *connection_map_init() {
46963 + connection_map *cm;
46965 + cm = calloc(1, sizeof(*cm));
46970 +void connection_map_free(connection_map *cm) {
46972 + for (i = 0; i < cm->size; i++) {
46973 + connection_map_entry *cme = cm->ptr[i];
46977 + if (cme->con_id) {
46978 + buffer_free(cme->con_id);
46986 +int connection_map_insert(connection_map *cm, connection *con, buffer *con_id) {
46987 + connection_map_entry *cme;
46990 + if (cm->size == 0) {
46992 + cm->ptr = malloc(cm->size * sizeof(*(cm->ptr)));
46993 + for (i = 0; i < cm->size; i++) {
46994 + cm->ptr[i] = NULL;
46996 + } else if (cm->used == cm->size) {
46998 + cm->ptr = realloc(cm->ptr, cm->size * sizeof(*(cm->ptr)));
46999 + for (i = cm->used; i < cm->size; i++) {
47000 + cm->ptr[i] = NULL;
47004 + if (cm->ptr[cm->used]) {
47005 + /* is already alloced, just reuse it */
47006 + cme = cm->ptr[cm->used];
47008 + cme = malloc(sizeof(*cme));
47010 + cme->con_id = buffer_init();
47011 + buffer_copy_string_buffer(cme->con_id, con_id);
47014 + cm->ptr[cm->used++] = cme;
47019 +connection *connection_map_get_connection(connection_map *cm, buffer *con_id) {
47022 + for (i = 0; i < cm->used; i++) {
47023 + connection_map_entry *cme = cm->ptr[i];
47025 + if (buffer_is_equal(cme->con_id, con_id)) {
47026 + /* found connection */
47034 +int connection_map_remove_connection(connection_map *cm, connection *con) {
47037 + for (i = 0; i < cm->used; i++) {
47038 + connection_map_entry *cme = cm->ptr[i];
47040 + if (cme->con == con) {
47041 + /* found connection */
47043 + buffer_reset(cme->con_id);
47048 + /* swap positions with the last entry */
47050 + cm->ptr[i] = cm->ptr[cm->used];
47051 + cm->ptr[cm->used] = cme;
47061 +/* init the plugin data */
47062 +INIT_FUNC(mod_uploadprogress_init) {
47065 + p = calloc(1, sizeof(*p));
47067 + p->con_map = connection_map_init();
47072 +/* detroy the plugin data */
47073 +FREE_FUNC(mod_uploadprogress_free) {
47074 + plugin_data *p = p_d;
47078 + if (!p) return HANDLER_GO_ON;
47080 + if (p->config_storage) {
47082 + for (i = 0; i < srv->config_context->used; i++) {
47083 + plugin_config *s = p->config_storage[i];
47085 + buffer_free(s->progress_url);
47089 + free(p->config_storage);
47092 + connection_map_free(p->con_map);
47096 + return HANDLER_GO_ON;
47099 +/* handle plugin config and check values */
47101 +SETDEFAULTS_FUNC(mod_uploadprogress_set_defaults) {
47102 + plugin_data *p = p_d;
47105 + config_values_t cv[] = {
47106 + { "upload-progress.progress-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
47107 + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
47110 + if (!p) return HANDLER_ERROR;
47112 + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
47114 + for (i = 0; i < srv->config_context->used; i++) {
47115 + plugin_config *s;
47117 + s = calloc(1, sizeof(plugin_config));
47118 + s->progress_url = buffer_init();
47120 + cv[0].destination = s->progress_url;
47122 + p->config_storage[i] = s;
47124 + if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
47125 + return HANDLER_ERROR;
47129 + return HANDLER_GO_ON;
47132 +static int mod_uploadprogress_patch_connection(server *srv, connection *con, plugin_data *p) {
47134 + plugin_config *s = p->config_storage[0];
47136 + PATCH_OPTION(progress_url);
47138 + /* skip the first, the global context */
47139 + for (i = 1; i < srv->config_context->used; i++) {
47140 + data_config *dc = (data_config *)srv->config_context->data[i];
47141 + s = p->config_storage[i];
47143 + /* condition didn't match */
47144 + if (!config_check_cond(srv, con, dc)) continue;
47146 + /* merge config */
47147 + for (j = 0; j < dc->value->used; j++) {
47148 + data_unset *du = dc->value->data[j];
47150 + if (buffer_is_equal_string(du->key, CONST_STR_LEN("upload-progress.progress-url"))) {
47151 + PATCH_OPTION(progress_url);
47163 + * for the first request we check if it is a post-request
47165 + * if no, move out, don't care about them
47167 + * if yes, take the connection structure and register it locally
47168 + * in the progress-struct together with an session-id (md5 ... )
47170 + * if the connections closes, cleanup the entry in the progress-struct
47172 + * a second request can now get the info about the size of the upload,
47173 + * the received bytes
47177 +URIHANDLER_FUNC(mod_uploadprogress_uri_handler) {
47178 + plugin_data *p = p_d;
47181 + buffer *b, *tracking_id;
47182 + connection *post_con = NULL;
47186 + if (con->uri.path->used == 0) return HANDLER_GO_ON;
47188 + mod_uploadprogress_patch_connection(srv, con, p);
47190 + /* check if this is a POST request */
47191 + switch(con->request.http_method) {
47192 + case HTTP_METHOD_POST:
47193 + /* the request has to contain a 32byte ID */
47195 + if (NULL == (ds = (data_string *)array_get_element(con->request.headers, "X-Progress-ID"))) {
47196 + if (!buffer_is_empty(con->uri.query)) {
47197 + /* perhaps the POST request is using the querystring to pass the X-Progress-ID */
47198 + b = con->uri.query;
47200 + return HANDLER_GO_ON;
47206 + if (b->used != 32 + 1) {
47207 + ERROR("the Progress-ID has to be 32 characters long, got %d characters", b->used - 1);
47209 + return HANDLER_GO_ON;
47212 + for (i = 0; i < b->used - 1; i++) {
47213 + char c = b->ptr[i];
47215 + if (!light_isxdigit(c)) {
47216 + ERROR("only hex-digits are allowed (0-9 + a-f): (ascii: %d)", c);
47218 + return HANDLER_GO_ON;
47222 + connection_map_insert(p->con_map, con, b);
47224 + return HANDLER_GO_ON;
47225 + case HTTP_METHOD_GET:
47226 + if (!buffer_is_equal(con->uri.path, p->conf.progress_url)) {
47227 + return HANDLER_GO_ON;
47230 + if (NULL == (ds = (data_string *)array_get_element(con->request.headers, "X-Progress-ID"))) {
47231 + if (!buffer_is_empty(con->uri.query)) {
47232 + /* perhaps the GET request is using the querystring to pass the X-Progress-ID */
47233 + tracking_id = con->uri.query;
47235 + return HANDLER_GO_ON;
47238 + tracking_id = ds->value;
47241 + if (tracking_id->used != 32 + 1) {
47242 + ERROR("the Progress-ID has to be 32 characters long, got %d characters", tracking_id->used - 1);
47244 + return HANDLER_GO_ON;
47247 + for (i = 0; i < tracking_id->used - 1; i++) {
47248 + char c = tracking_id->ptr[i];
47250 + if (!light_isxdigit(c)) {
47251 + ERROR("only hex-digits are allowed (0-9 + a-f): (ascii: %d)", c);
47253 + return HANDLER_GO_ON;
47257 + buffer_reset(con->physical.path);
47259 + con->file_started = 1;
47260 + con->http_status = 200;
47261 + con->send->is_closed = 1;
47263 + /* send JSON content */
47265 + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/javascript"));
47267 + /* just an attempt the force the IE/proxies to NOT cache the request */
47268 + response_header_overwrite(srv, con, CONST_STR_LEN("Pragma"), CONST_STR_LEN("no-cache"));
47269 + response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_STR_LEN("Thu, 19 Nov 1981 08:52:00 GMT"));
47270 + response_header_overwrite(srv, con, CONST_STR_LEN("Cache-Control"),
47271 + CONST_STR_LEN("no-store, no-cache, must-revalidate, post-check=0, pre-check=0"));
47273 + b = chunkqueue_get_append_buffer(con->send);
47275 + /* get the connection */
47276 + if (NULL == (post_con = connection_map_get_connection(p->con_map, tracking_id))) {
47277 + BUFFER_APPEND_STRING_CONST(b, "new Object({ 'status' : 'starting' })\r\n");
47279 + return HANDLER_FINISHED;
47282 + /* prepare XML */
47283 + BUFFER_COPY_STRING_CONST(b, "new Object({ 'state' : ");
47284 + buffer_append_string(b, post_con->recv->is_closed ? "'done'" : "'uploading'");
47285 + BUFFER_APPEND_STRING_CONST(b, ", 'size' : ");
47286 + buffer_append_off_t(b, post_con->request.content_length == -1 ? 0 : post_con->request.content_length);
47287 + BUFFER_APPEND_STRING_CONST(b, ", 'received' : ");
47288 + buffer_append_off_t(b, post_con->recv->bytes_in);
47289 + BUFFER_APPEND_STRING_CONST(b, "})\r\n");
47291 + return HANDLER_FINISHED;
47296 + return HANDLER_GO_ON;
47299 +REQUESTDONE_FUNC(mod_uploadprogress_request_done) {
47300 + plugin_data *p = p_d;
47304 + if (con->uri.path->used == 0) return HANDLER_GO_ON;
47306 + if (connection_map_remove_connection(p->con_map, con)) {
47310 + return HANDLER_GO_ON;
47313 +/* this function is called at dlopen() time and inits the callbacks */
47315 +int mod_uploadprogress_plugin_init(plugin *p) {
47316 + p->version = LIGHTTPD_VERSION_ID;
47317 + p->name = buffer_init_string("uploadprogress");
47319 + p->init = mod_uploadprogress_init;
47320 + p->handle_uri_clean = mod_uploadprogress_uri_handler;
47321 + p->handle_response_done = mod_uploadprogress_request_done;
47322 + p->set_defaults = mod_uploadprogress_set_defaults;
47323 + p->cleanup = mod_uploadprogress_free;
47329 --- ../lighttpd-1.4.11/src/mod_userdir.c 2005-10-28 16:48:28.000000000 +0300
47330 +++ lighttpd-1.5.0/src/mod_userdir.c 2006-07-16 00:26:04.000000000 +0300
47332 #include "response.h"
47334 #include "plugin.h"
47335 +#include "sys-files.h"
47339 @@ -25,54 +26,54 @@
47349 plugin_config **config_storage;
47351 - plugin_config conf;
47353 + plugin_config conf;
47356 /* init the plugin data */
47357 INIT_FUNC(mod_userdir_init) {
47361 p = calloc(1, sizeof(*p));
47364 p->username = buffer_init();
47365 p->temp_path = buffer_init();
47371 /* detroy the plugin data */
47372 FREE_FUNC(mod_userdir_free) {
47373 plugin_data *p = p_d;
47376 if (!p) return HANDLER_GO_ON;
47379 if (p->config_storage) {
47383 for (i = 0; i < srv->config_context->used; i++) {
47384 plugin_config *s = p->config_storage[i];
47387 array_free(s->include_user);
47388 array_free(s->exclude_user);
47389 buffer_free(s->path);
47390 buffer_free(s->basepath);
47395 free(p->config_storage);
47399 buffer_free(p->username);
47400 buffer_free(p->temp_path);
47406 return HANDLER_GO_ON;
47409 @@ -81,81 +82,78 @@
47410 SETDEFAULTS_FUNC(mod_userdir_set_defaults) {
47411 plugin_data *p = p_d;
47414 - config_values_t cv[] = {
47416 + config_values_t cv[] = {
47417 { "userdir.path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
47418 { "userdir.exclude-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
47419 { "userdir.include-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
47420 { "userdir.basepath", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
47421 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
47425 if (!p) return HANDLER_ERROR;
47428 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
47431 for (i = 0; i < srv->config_context->used; i++) {
47435 s = calloc(1, sizeof(plugin_config));
47436 s->exclude_user = array_init();
47437 s->include_user = array_init();
47438 s->path = buffer_init();
47439 s->basepath = buffer_init();
47442 cv[0].destination = s->path;
47443 cv[1].destination = s->exclude_user;
47444 cv[2].destination = s->include_user;
47445 cv[3].destination = s->basepath;
47448 p->config_storage[i] = s;
47451 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
47452 return HANDLER_ERROR;
47457 return HANDLER_GO_ON;
47460 -#define PATCH(x) \
47461 - p->conf.x = s->x;
47462 static int mod_userdir_patch_connection(server *srv, connection *con, plugin_data *p) {
47464 plugin_config *s = p->config_storage[0];
47467 - PATCH(exclude_user);
47468 - PATCH(include_user);
47472 + PATCH_OPTION(path);
47473 + PATCH_OPTION(exclude_user);
47474 + PATCH_OPTION(include_user);
47475 + PATCH_OPTION(basepath);
47477 /* skip the first, the global context */
47478 for (i = 1; i < srv->config_context->used; i++) {
47479 data_config *dc = (data_config *)srv->config_context->data[i];
47480 s = p->config_storage[i];
47483 /* condition didn't match */
47484 if (!config_check_cond(srv, con, dc)) continue;
47488 for (j = 0; j < dc->value->used; j++) {
47489 data_unset *du = dc->value->data[j];
47492 if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.path"))) {
47494 + PATCH_OPTION(path);
47495 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.exclude-user"))) {
47496 - PATCH(exclude_user);
47497 + PATCH_OPTION(exclude_user);
47498 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.include-user"))) {
47499 - PATCH(include_user);
47500 + PATCH_OPTION(include_user);
47501 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.basepath"))) {
47503 + PATCH_OPTION(basepath);
47513 URIHANDLER_FUNC(mod_userdir_docroot_handler) {
47514 plugin_data *p = p_d;
47515 @@ -169,18 +167,18 @@
47516 if (con->uri.path->used == 0) return HANDLER_GO_ON;
47518 mod_userdir_patch_connection(srv, con, p);
47521 uri_len = con->uri.path->used - 1;
47524 /* /~user/foo.html -> /home/user/public_html/foo.html */
47527 if (con->uri.path->ptr[0] != '/' ||
47528 con->uri.path->ptr[1] != '~') return HANDLER_GO_ON;
47531 if (NULL == (rel_url = strchr(con->uri.path->ptr + 2, '/'))) {
47532 /* / is missing -> redirect to .../ as we are a user - DIRECTORY ! :) */
47533 http_response_redirect_to_directory(srv, con);
47536 return HANDLER_FINISHED;
47539 @@ -188,10 +186,10 @@
47540 if (0 == rel_url - (con->uri.path->ptr + 2)) {
47541 return HANDLER_GO_ON;
47545 buffer_copy_string_len(p->username, con->uri.path->ptr + 2, rel_url - (con->uri.path->ptr + 2));
47547 - if (buffer_is_empty(p->conf.basepath)
47549 + if (buffer_is_empty(p->conf.basepath)
47551 && NULL == (pwd = getpwnam(p->username->ptr))
47553 @@ -200,31 +198,31 @@
47554 return HANDLER_GO_ON;
47559 for (k = 0; k < p->conf.exclude_user->used; k++) {
47560 data_string *ds = (data_string *)p->conf.exclude_user->data[k];
47563 if (buffer_is_equal(ds->value, p->username)) {
47564 /* user in exclude list */
47565 return HANDLER_GO_ON;
47570 if (p->conf.include_user->used) {
47571 int found_user = 0;
47572 for (k = 0; k < p->conf.include_user->used; k++) {
47573 data_string *ds = (data_string *)p->conf.include_user->data[k];
47576 if (buffer_is_equal(ds->value, p->username)) {
47577 /* user in include list */
47584 if (!found_user) return HANDLER_GO_ON;
47588 /* we build the physical path */
47590 if (buffer_is_empty(p->conf.basepath)) {
47591 @@ -252,23 +250,23 @@
47594 buffer_copy_string_buffer(p->temp_path, p->conf.basepath);
47595 - BUFFER_APPEND_SLASH(p->temp_path);
47596 + PATHNAME_APPEND_SLASH(p->temp_path);
47597 buffer_append_string_buffer(p->temp_path, p->username);
47599 - BUFFER_APPEND_SLASH(p->temp_path);
47600 - buffer_append_string_buffer(p->temp_path, p->conf.path);
47601 + PATHNAME_APPEND_SLASH(p->temp_path);
47602 + buffer_append_string_buffer(p->temp_path, p->conf.path);
47604 if (buffer_is_empty(p->conf.basepath)) {
47609 ret = stat(p->temp_path->ptr, &st);
47610 if (ret < 0 || S_ISDIR(st.st_mode) != 1) {
47611 return HANDLER_GO_ON;
47616 - BUFFER_APPEND_SLASH(p->temp_path);
47617 + PATHNAME_APPEND_SLASH(p->temp_path);
47618 buffer_append_string(p->temp_path, rel_url + 1); /* skip the / */
47619 buffer_copy_string_buffer(con->physical.path, p->temp_path);
47621 @@ -282,13 +280,13 @@
47622 int mod_userdir_plugin_init(plugin *p) {
47623 p->version = LIGHTTPD_VERSION_ID;
47624 p->name = buffer_init_string("userdir");
47627 p->init = mod_userdir_init;
47628 p->handle_physical = mod_userdir_docroot_handler;
47629 p->set_defaults = mod_userdir_set_defaults;
47630 p->cleanup = mod_userdir_free;
47638 --- ../lighttpd-1.4.11/src/mod_usertrack.c 2006-01-31 15:01:20.000000000 +0200
47639 +++ lighttpd-1.5.0/src/mod_usertrack.c 2006-07-16 00:26:04.000000000 +0300
47640 @@ -24,44 +24,44 @@
47646 plugin_config **config_storage;
47648 - plugin_config conf;
47650 + plugin_config conf;
47653 /* init the plugin data */
47654 INIT_FUNC(mod_usertrack_init) {
47658 p = calloc(1, sizeof(*p));
47664 /* detroy the plugin data */
47665 FREE_FUNC(mod_usertrack_free) {
47666 plugin_data *p = p_d;
47672 if (!p) return HANDLER_GO_ON;
47675 if (p->config_storage) {
47677 for (i = 0; i < srv->config_context->used; i++) {
47678 plugin_config *s = p->config_storage[i];
47681 buffer_free(s->cookie_name);
47682 buffer_free(s->cookie_domain);
47687 free(p->config_storage);
47694 return HANDLER_GO_ON;
47697 @@ -70,38 +70,38 @@
47698 SETDEFAULTS_FUNC(mod_usertrack_set_defaults) {
47699 plugin_data *p = p_d;
47702 - config_values_t cv[] = {
47704 + config_values_t cv[] = {
47705 { "usertrack.cookie-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
47706 { "usertrack.cookie-max-age", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
47707 { "usertrack.cookie-domain", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
47709 - { "usertrack.cookiename", NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },
47711 + { "usertrack.cookiename", NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },
47712 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
47716 if (!p) return HANDLER_ERROR;
47719 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
47722 for (i = 0; i < srv->config_context->used; i++) {
47726 s = calloc(1, sizeof(plugin_config));
47727 s->cookie_name = buffer_init();
47728 s->cookie_domain = buffer_init();
47729 s->cookie_max_age = 0;
47732 cv[0].destination = s->cookie_name;
47733 cv[1].destination = &(s->cookie_max_age);
47734 cv[2].destination = s->cookie_domain;
47737 p->config_storage[i] = s;
47740 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
47741 return HANDLER_ERROR;
47745 if (buffer_is_empty(s->cookie_name)) {
47746 buffer_copy_string(s->cookie_name, "TRACKID");
47748 @@ -109,68 +109,65 @@
47749 for (j = 0; j < s->cookie_name->used - 1; j++) {
47750 char c = s->cookie_name->ptr[j] | 32;
47751 if (c < 'a' || c > 'z') {
47752 - log_error_write(srv, __FILE__, __LINE__, "sb",
47753 - "invalid character in usertrack.cookie-name:",
47754 + log_error_write(srv, __FILE__, __LINE__, "sb",
47755 + "invalid character in usertrack.cookie-name:",
47759 return HANDLER_ERROR;
47765 if (!buffer_is_empty(s->cookie_domain)) {
47767 for (j = 0; j < s->cookie_domain->used - 1; j++) {
47768 char c = s->cookie_domain->ptr[j];
47769 if (c <= 32 || c >= 127 || c == '"' || c == '\\') {
47770 - log_error_write(srv, __FILE__, __LINE__, "sb",
47771 - "invalid character in usertrack.cookie-domain:",
47772 + log_error_write(srv, __FILE__, __LINE__, "sb",
47773 + "invalid character in usertrack.cookie-domain:",
47777 return HANDLER_ERROR;
47784 return HANDLER_GO_ON;
47787 -#define PATCH(x) \
47788 - p->conf.x = s->x;
47789 static int mod_usertrack_patch_connection(server *srv, connection *con, plugin_data *p) {
47791 plugin_config *s = p->config_storage[0];
47793 - PATCH(cookie_name);
47794 - PATCH(cookie_domain);
47795 - PATCH(cookie_max_age);
47798 + PATCH_OPTION(cookie_name);
47799 + PATCH_OPTION(cookie_domain);
47800 + PATCH_OPTION(cookie_max_age);
47802 /* skip the first, the global context */
47803 for (i = 1; i < srv->config_context->used; i++) {
47804 data_config *dc = (data_config *)srv->config_context->data[i];
47805 s = p->config_storage[i];
47808 /* condition didn't match */
47809 if (!config_check_cond(srv, con, dc)) continue;
47813 for (j = 0; j < dc->value->used; j++) {
47814 data_unset *du = dc->value->data[j];
47817 if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-name"))) {
47818 - PATCH(cookie_name);
47819 + PATCH_OPTION(cookie_name);
47820 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-max-age"))) {
47821 - PATCH(cookie_max_age);
47822 + PATCH_OPTION(cookie_max_age);
47823 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-domain"))) {
47824 - PATCH(cookie_domain);
47825 + PATCH_OPTION(cookie_domain);
47835 URIHANDLER_FUNC(mod_usertrack_uri_handler) {
47836 plugin_data *p = p_d;
47837 @@ -178,38 +175,38 @@
47838 unsigned char h[16];
47843 if (con->uri.path->used == 0) return HANDLER_GO_ON;
47846 mod_usertrack_patch_connection(srv, con, p);
47849 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
47851 /* we have a cookie, does it contain a valid name ? */
47853 - /* parse the cookie
47856 + /* parse the cookie
47858 * check for cookiename + (WS | '=')
47864 if (NULL != (g = strstr(ds->value->ptr, p->conf.cookie_name->ptr))) {
47869 for (nc = g + p->conf.cookie_name->used-1; *nc == ' ' || *nc == '\t'; nc++);
47873 /* ok, found the key of our own cookie */
47876 if (strlen(nc) > 32) {
47878 return HANDLER_GO_ON;
47887 if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
47888 ds = data_response_init();
47889 @@ -217,39 +214,39 @@
47890 buffer_copy_string(ds->key, "Set-Cookie");
47891 buffer_copy_string_buffer(ds->value, p->conf.cookie_name);
47892 buffer_append_string(ds->value, "=");
47896 /* taken from mod_auth.c */
47899 /* generate shared-secret */
47901 MD5_Update(&Md5Ctx, (unsigned char *)con->uri.path->ptr, con->uri.path->used - 1);
47902 MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
47905 /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
47906 ltostr(hh, srv->cur_ts);
47907 MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
47908 ltostr(hh, rand());
47909 MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
47912 MD5_Final(h, &Md5Ctx);
47915 buffer_append_string_encoded(ds->value, (char *)h, 16, ENCODING_HEX);
47916 buffer_append_string(ds->value, "; Path=/");
47917 buffer_append_string(ds->value, "; Version=1");
47920 if (!buffer_is_empty(p->conf.cookie_domain)) {
47921 buffer_append_string(ds->value, "; Domain=");
47922 buffer_append_string_encoded(ds->value, CONST_BUF_LEN(p->conf.cookie_domain), ENCODING_REL_URI);
47926 if (p->conf.cookie_max_age) {
47927 buffer_append_string(ds->value, "; max-age=");
47928 buffer_append_long(ds->value, p->conf.cookie_max_age);
47932 array_insert_unique(con->response.headers, (data_unset *)ds);
47935 return HANDLER_GO_ON;
47938 @@ -258,13 +255,13 @@
47939 int mod_usertrack_plugin_init(plugin *p) {
47940 p->version = LIGHTTPD_VERSION_ID;
47941 p->name = buffer_init_string("usertrack");
47944 p->init = mod_usertrack_init;
47945 p->handle_uri_clean = mod_usertrack_uri_handler;
47946 p->set_defaults = mod_usertrack_set_defaults;
47947 p->cleanup = mod_usertrack_free;
47955 --- ../lighttpd-1.4.11/src/mod_webdav.c 2006-03-03 01:28:58.000000000 +0200
47956 +++ lighttpd-1.5.0/src/mod_webdav.c 2006-09-07 00:57:05.000000000 +0300
47959 #include <stdlib.h>
47960 #include <string.h>
47961 -#include <dirent.h>
47963 -#include <unistd.h>
47966 #include <assert.h>
47967 -#include <sys/mman.h>
47969 #ifdef HAVE_CONFIG_H
47970 #include "config.h"
47972 #include <sqlite3.h>
47975 +#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H) && defined(HAVE_UUID_H)
47977 +#include <uuid/uuid.h>
47982 #include "buffer.h"
47983 @@ -33,13 +35,16 @@
47984 #include "stream.h"
47985 #include "stat_cache.h"
47987 +#include "sys-files.h"
47988 +#include "sys-mmap.h"
47989 +#include "sys-strings.h"
47992 * this is a webdav for a lighttpd plugin
47994 - * at least a very basic one.
47995 + * at least a very basic one.
47996 * - for now it is read-only and we only support PROPFIND
48002 @@ -58,64 +63,70 @@
48003 sqlite3_stmt *stmt_delete_prop;
48004 sqlite3_stmt *stmt_select_prop;
48005 sqlite3_stmt *stmt_select_propnames;
48008 sqlite3_stmt *stmt_delete_uri;
48009 sqlite3_stmt *stmt_move_uri;
48010 sqlite3_stmt *stmt_copy_uri;
48012 + sqlite3_stmt *stmt_remove_lock;
48013 + sqlite3_stmt *stmt_create_lock;
48014 + sqlite3_stmt *stmt_read_lock;
48015 + sqlite3_stmt *stmt_read_lock_by_uri;
48016 + sqlite3_stmt *stmt_refresh_lock;
48028 plugin_config **config_storage;
48030 - plugin_config conf;
48032 + plugin_config conf;
48035 /* init the plugin data */
48036 INIT_FUNC(mod_webdav_init) {
48040 p = calloc(1, sizeof(*p));
48043 p->tmp_buf = buffer_init();
48045 p->uri.scheme = buffer_init();
48046 p->uri.path_raw = buffer_init();
48047 p->uri.path = buffer_init();
48048 p->uri.authority = buffer_init();
48051 p->physical.path = buffer_init();
48052 p->physical.rel_path = buffer_init();
48053 p->physical.doc_root = buffer_init();
48054 p->physical.basedir = buffer_init();
48060 /* detroy the plugin data */
48061 FREE_FUNC(mod_webdav_free) {
48062 plugin_data *p = p_d;
48067 if (!p) return HANDLER_GO_ON;
48070 if (p->config_storage) {
48072 for (i = 0; i < srv->config_context->used; i++) {
48073 plugin_config *s = p->config_storage[i];
48078 buffer_free(s->sqlite_db_name);
48079 #ifdef USE_PROPPATCH
48082 sqlite3_finalize(s->stmt_delete_prop);
48083 sqlite3_finalize(s->stmt_delete_uri);
48084 sqlite3_finalize(s->stmt_copy_uri);
48085 @@ -123,9 +134,15 @@
48086 sqlite3_finalize(s->stmt_update_prop);
48087 sqlite3_finalize(s->stmt_select_prop);
48088 sqlite3_finalize(s->stmt_select_propnames);
48090 + sqlite3_finalize(s->stmt_read_lock);
48091 + sqlite3_finalize(s->stmt_read_lock_by_uri);
48092 + sqlite3_finalize(s->stmt_create_lock);
48093 + sqlite3_finalize(s->stmt_remove_lock);
48094 + sqlite3_finalize(s->stmt_refresh_lock);
48095 sqlite3_close(s->sql);
48101 free(p->config_storage);
48102 @@ -135,16 +152,16 @@
48103 buffer_free(p->uri.path_raw);
48104 buffer_free(p->uri.path);
48105 buffer_free(p->uri.authority);
48108 buffer_free(p->physical.path);
48109 buffer_free(p->physical.rel_path);
48110 buffer_free(p->physical.doc_root);
48111 buffer_free(p->physical.basedir);
48114 buffer_free(p->tmp_buf);
48120 return HANDLER_GO_ON;
48123 @@ -153,32 +170,32 @@
48124 SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
48125 plugin_data *p = p_d;
48128 - config_values_t cv[] = {
48130 + config_values_t cv[] = {
48131 { "webdav.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
48132 { "webdav.is-readonly", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
48133 { "webdav.sqlite-db-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
48134 { "webdav.log-xml", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
48135 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
48139 if (!p) return HANDLER_ERROR;
48142 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
48145 for (i = 0; i < srv->config_context->used; i++) {
48149 s = calloc(1, sizeof(plugin_config));
48150 s->sqlite_db_name = buffer_init();
48153 cv[0].destination = &(s->enabled);
48154 cv[1].destination = &(s->is_readonly);
48155 cv[2].destination = s->sqlite_db_name;
48156 cv[3].destination = &(s->log_xml);
48159 p->config_storage[i] = s;
48162 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
48163 return HANDLER_ERROR;
48165 @@ -193,8 +210,26 @@
48166 return HANDLER_ERROR;
48169 - if (SQLITE_OK != sqlite3_prepare(s->sql,
48170 - CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
48171 + if (SQLITE_OK != sqlite3_exec(s->sql,
48172 + "CREATE TABLE properties ("
48173 + " resource TEXT NOT NULL,"
48174 + " prop TEXT NOT NULL,"
48175 + " ns TEXT NOT NULL,"
48176 + " value TEXT NOT NULL,"
48177 + " PRIMARY KEY(resource, prop, ns))",
48178 + NULL, NULL, &err)) {
48180 + if (0 != strcmp(err, "table properties already exists")) {
48181 + log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
48182 + sqlite3_free(err);
48184 + return HANDLER_ERROR;
48186 + sqlite3_free(err);
48189 + if (SQLITE_OK != sqlite3_prepare(s->sql,
48190 + CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
48191 &(s->stmt_select_prop), &next_stmt)) {
48192 /* prepare failed */
48194 @@ -202,8 +237,8 @@
48195 return HANDLER_ERROR;
48198 - if (SQLITE_OK != sqlite3_prepare(s->sql,
48199 - CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"),
48200 + if (SQLITE_OK != sqlite3_prepare(s->sql,
48201 + CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"),
48202 &(s->stmt_select_propnames), &next_stmt)) {
48203 /* prepare failed */
48205 @@ -211,16 +246,67 @@
48206 return HANDLER_ERROR;
48209 - if (SQLITE_OK != sqlite3_exec(s->sql,
48210 - "CREATE TABLE properties ("
48212 + if (SQLITE_OK != sqlite3_prepare(s->sql,
48213 + CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"),
48214 + &(s->stmt_update_prop), &next_stmt)) {
48215 + /* prepare failed */
48217 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
48218 + return HANDLER_ERROR;
48221 + if (SQLITE_OK != sqlite3_prepare(s->sql,
48222 + CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
48223 + &(s->stmt_delete_prop), &next_stmt)) {
48224 + /* prepare failed */
48225 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48227 + return HANDLER_ERROR;
48230 + if (SQLITE_OK != sqlite3_prepare(s->sql,
48231 + CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"),
48232 + &(s->stmt_delete_uri), &next_stmt)) {
48233 + /* prepare failed */
48234 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48236 + return HANDLER_ERROR;
48239 + if (SQLITE_OK != sqlite3_prepare(s->sql,
48240 + CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"),
48241 + &(s->stmt_copy_uri), &next_stmt)) {
48242 + /* prepare failed */
48243 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48245 + return HANDLER_ERROR;
48248 + if (SQLITE_OK != sqlite3_prepare(s->sql,
48249 + CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"),
48250 + &(s->stmt_move_uri), &next_stmt)) {
48251 + /* prepare failed */
48252 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48254 + return HANDLER_ERROR;
48259 + if (SQLITE_OK != sqlite3_exec(s->sql,
48260 + "CREATE TABLE locks ("
48261 + " locktoken TEXT NOT NULL,"
48262 " resource TEXT NOT NULL,"
48263 - " prop TEXT NOT NULL,"
48264 - " ns TEXT NOT NULL,"
48265 - " value TEXT NOT NULL,"
48266 - " PRIMARY KEY(resource, prop, ns))",
48267 + " lockscope TEXT NOT NULL,"
48268 + " locktype TEXT NOT NULL,"
48269 + " owner TEXT NOT NULL,"
48270 + " depth INT NOT NULL,"
48271 + " timeout TIMESTAMP NOT NULL,"
48272 + " PRIMARY KEY(locktoken))",
48273 NULL, NULL, &err)) {
48275 - if (0 != strcmp(err, "table properties already exists")) {
48276 + if (0 != strcmp(err, "table locks already exists")) {
48277 log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
48280 @@ -228,127 +314,138 @@
48285 - if (SQLITE_OK != sqlite3_prepare(s->sql,
48286 - CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"),
48287 - &(s->stmt_update_prop), &next_stmt)) {
48289 + if (SQLITE_OK != sqlite3_prepare(s->sql,
48290 + CONST_STR_LEN("INSERT INTO locks (locktoken, resource, lockscope, locktype, owner, depth, timeout) VALUES (?,?,?,?,?,?, CURRENT_TIME + 600)"),
48291 + &(s->stmt_create_lock), &next_stmt)) {
48292 /* prepare failed */
48293 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48295 - log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
48296 return HANDLER_ERROR;
48299 - if (SQLITE_OK != sqlite3_prepare(s->sql,
48300 - CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
48301 - &(s->stmt_delete_prop), &next_stmt)) {
48302 + if (SQLITE_OK != sqlite3_prepare(s->sql,
48303 + CONST_STR_LEN("DELETE FROM locks WHERE locktoken = ?"),
48304 + &(s->stmt_remove_lock), &next_stmt)) {
48305 /* prepare failed */
48306 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48308 return HANDLER_ERROR;
48311 - if (SQLITE_OK != sqlite3_prepare(s->sql,
48312 - CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"),
48313 - &(s->stmt_delete_uri), &next_stmt)) {
48314 + if (SQLITE_OK != sqlite3_prepare(s->sql,
48315 + CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE locktoken = ?"),
48316 + &(s->stmt_read_lock), &next_stmt)) {
48317 /* prepare failed */
48318 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48320 return HANDLER_ERROR;
48323 - if (SQLITE_OK != sqlite3_prepare(s->sql,
48324 - CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"),
48325 - &(s->stmt_copy_uri), &next_stmt)) {
48326 + if (SQLITE_OK != sqlite3_prepare(s->sql,
48327 + CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE resource = ?"),
48328 + &(s->stmt_read_lock_by_uri), &next_stmt)) {
48329 /* prepare failed */
48330 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48332 return HANDLER_ERROR;
48335 - if (SQLITE_OK != sqlite3_prepare(s->sql,
48336 - CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"),
48337 - &(s->stmt_move_uri), &next_stmt)) {
48338 + if (SQLITE_OK != sqlite3_prepare(s->sql,
48339 + CONST_STR_LEN("UPDATE locks SET timeout = CURRENT_TIME + 600 WHERE locktoken = ?"),
48340 + &(s->stmt_refresh_lock), &next_stmt)) {
48341 /* prepare failed */
48342 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48344 return HANDLER_ERROR;
48349 log_error_write(srv, __FILE__, __LINE__, "s", "Sorry, no sqlite3 and libxml2 support include, compile with --with-webdav-props");
48350 return HANDLER_ERROR;
48356 return HANDLER_GO_ON;
48359 -#define PATCH(x) \
48360 - p->conf.x = s->x;
48361 static int mod_webdav_patch_connection(server *srv, connection *con, plugin_data *p) {
48363 plugin_config *s = p->config_storage[0];
48366 - PATCH(is_readonly);
48370 + PATCH_OPTION(enabled);
48371 + PATCH_OPTION(is_readonly);
48372 + PATCH_OPTION(log_xml);
48374 #ifdef USE_PROPPATCH
48376 - PATCH(stmt_update_prop);
48377 - PATCH(stmt_delete_prop);
48378 - PATCH(stmt_select_prop);
48379 - PATCH(stmt_select_propnames);
48381 - PATCH(stmt_delete_uri);
48382 - PATCH(stmt_move_uri);
48383 - PATCH(stmt_copy_uri);
48384 + PATCH_OPTION(sql);
48385 + PATCH_OPTION(stmt_update_prop);
48386 + PATCH_OPTION(stmt_delete_prop);
48387 + PATCH_OPTION(stmt_select_prop);
48388 + PATCH_OPTION(stmt_select_propnames);
48390 + PATCH_OPTION(stmt_delete_uri);
48391 + PATCH_OPTION(stmt_move_uri);
48392 + PATCH_OPTION(stmt_copy_uri);
48394 + PATCH_OPTION(stmt_remove_lock);
48395 + PATCH_OPTION(stmt_refresh_lock);
48396 + PATCH_OPTION(stmt_create_lock);
48397 + PATCH_OPTION(stmt_read_lock);
48398 + PATCH_OPTION(stmt_read_lock_by_uri);
48400 /* skip the first, the global context */
48401 for (i = 1; i < srv->config_context->used; i++) {
48402 data_config *dc = (data_config *)srv->config_context->data[i];
48403 s = p->config_storage[i];
48406 /* condition didn't match */
48407 if (!config_check_cond(srv, con, dc)) continue;
48411 for (j = 0; j < dc->value->used; j++) {
48412 data_unset *du = dc->value->data[j];
48415 if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.activate"))) {
48417 + PATCH_OPTION(enabled);
48418 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.is-readonly"))) {
48419 - PATCH(is_readonly);
48420 + PATCH_OPTION(is_readonly);
48421 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.log-xml"))) {
48423 + PATCH_OPTION(log_xml);
48424 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.sqlite-db-name"))) {
48425 #ifdef USE_PROPPATCH
48427 - PATCH(stmt_update_prop);
48428 - PATCH(stmt_delete_prop);
48429 - PATCH(stmt_select_prop);
48430 - PATCH(stmt_select_propnames);
48432 - PATCH(stmt_delete_uri);
48433 - PATCH(stmt_move_uri);
48434 - PATCH(stmt_copy_uri);
48435 + PATCH_OPTION(sql);
48436 + PATCH_OPTION(stmt_update_prop);
48437 + PATCH_OPTION(stmt_delete_prop);
48438 + PATCH_OPTION(stmt_select_prop);
48439 + PATCH_OPTION(stmt_select_propnames);
48441 + PATCH_OPTION(stmt_delete_uri);
48442 + PATCH_OPTION(stmt_move_uri);
48443 + PATCH_OPTION(stmt_copy_uri);
48445 + PATCH_OPTION(stmt_remove_lock);
48446 + PATCH_OPTION(stmt_refresh_lock);
48447 + PATCH_OPTION(stmt_create_lock);
48448 + PATCH_OPTION(stmt_read_lock);
48449 + PATCH_OPTION(stmt_read_lock_by_uri);
48460 URIHANDLER_FUNC(mod_webdav_uri_handler) {
48461 plugin_data *p = p_d;
48466 if (con->uri.path->used == 0) return HANDLER_GO_ON;
48469 mod_webdav_patch_connection(srv, con, p);
48471 if (!p->conf.enabled) return HANDLER_GO_ON;
48472 @@ -362,20 +459,20 @@
48473 if (p->conf.is_readonly) {
48474 response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND"));
48476 - response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH"));
48477 + response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH, LOCK, UNLOCK"));
48486 return HANDLER_GO_ON;
48488 -static int webdav_gen_prop_tag(server *srv, connection *con,
48492 +static int webdav_gen_prop_tag(server *srv, connection *con,
48499 @@ -414,7 +511,7 @@
48500 buffer_append_string_buffer(b, dst->rel_path);
48501 buffer_append_string(b,"</D:href>\n");
48502 buffer_append_string(b,"<D:status>\n");
48505 if (con->request.http_version == HTTP_VERSION_1_1) {
48506 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
48508 @@ -458,14 +555,13 @@
48510 /* bind the values to the insert */
48512 - sqlite3_bind_text(stmt, 1,
48513 - dst->rel_path->ptr,
48514 + sqlite3_bind_text(stmt, 1,
48515 + dst->rel_path->ptr,
48516 dst->rel_path->used - 1,
48520 if (SQLITE_DONE != sqlite3_step(stmt)) {
48526 @@ -493,14 +589,14 @@
48527 (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
48529 /* ignore the parent dir */
48533 buffer_copy_string_buffer(d.path, dst->path);
48534 - BUFFER_APPEND_SLASH(d.path);
48535 + PATHNAME_APPEND_SLASH(d.path);
48536 buffer_append_string(d.path, de->d_name);
48539 buffer_copy_string_buffer(d.rel_path, dst->rel_path);
48540 - BUFFER_APPEND_SLASH(d.rel_path);
48541 + PATHNAME_APPEND_SLASH(d.rel_path);
48542 buffer_append_string(d.rel_path, de->d_name);
48544 /* stat and unlink afterwards */
48545 @@ -508,7 +604,7 @@
48546 /* don't about it yet, rmdir will fail too */
48547 } else if (S_ISDIR(st.st_mode)) {
48548 have_multi_status = webdav_delete_dir(srv, con, p, &d, b);
48551 /* try to unlink it */
48552 if (-1 == rmdir(d.path->ptr)) {
48554 @@ -535,14 +631,13 @@
48556 /* bind the values to the insert */
48558 - sqlite3_bind_text(stmt, 1,
48560 + sqlite3_bind_text(stmt, 1,
48562 d.rel_path->used - 1,
48566 if (SQLITE_DONE != sqlite3_step(stmt)) {
48572 @@ -569,7 +664,7 @@
48573 if (stream_open(&s, src->path)) {
48578 if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), 0600))) {
48579 /* opening the destination failed for some reason */
48581 @@ -601,7 +696,7 @@
48590 @@ -614,19 +709,18 @@
48591 sqlite3_reset(stmt);
48593 /* bind the values to the insert */
48594 - sqlite3_bind_text(stmt, 1,
48595 - dst->rel_path->ptr,
48596 + sqlite3_bind_text(stmt, 1,
48597 + dst->rel_path->ptr,
48598 dst->rel_path->used - 1,
48601 - sqlite3_bind_text(stmt, 2,
48602 - src->rel_path->ptr,
48603 + sqlite3_bind_text(stmt, 2,
48604 + src->rel_path->ptr,
48605 src->rel_path->used - 1,
48609 if (SQLITE_DONE != sqlite3_step(stmt)) {
48615 @@ -655,21 +749,21 @@
48616 (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
48621 buffer_copy_string_buffer(s.path, src->path);
48622 - BUFFER_APPEND_SLASH(s.path);
48623 + PATHNAME_APPEND_SLASH(s.path);
48624 buffer_append_string(s.path, de->d_name);
48626 buffer_copy_string_buffer(d.path, dst->path);
48627 - BUFFER_APPEND_SLASH(d.path);
48628 + PATHNAME_APPEND_SLASH(d.path);
48629 buffer_append_string(d.path, de->d_name);
48631 buffer_copy_string_buffer(s.rel_path, src->rel_path);
48632 - BUFFER_APPEND_SLASH(s.rel_path);
48633 + PATHNAME_APPEND_SLASH(s.rel_path);
48634 buffer_append_string(s.rel_path, de->d_name);
48636 buffer_copy_string_buffer(d.rel_path, dst->rel_path);
48637 - BUFFER_APPEND_SLASH(d.rel_path);
48638 + PATHNAME_APPEND_SLASH(d.rel_path);
48639 buffer_append_string(d.rel_path, de->d_name);
48641 if (-1 == stat(s.path->ptr, &st)) {
48642 @@ -692,19 +786,18 @@
48643 sqlite3_reset(stmt);
48645 /* bind the values to the insert */
48646 - sqlite3_bind_text(stmt, 1,
48647 - dst->rel_path->ptr,
48648 + sqlite3_bind_text(stmt, 1,
48649 + dst->rel_path->ptr,
48650 dst->rel_path->used - 1,
48653 - sqlite3_bind_text(stmt, 2,
48654 - src->rel_path->ptr,
48655 + sqlite3_bind_text(stmt, 2,
48656 + src->rel_path->ptr,
48657 src->rel_path->used - 1,
48661 if (SQLITE_DONE != sqlite3_step(stmt)) {
48667 @@ -721,7 +814,7 @@
48668 buffer_free(s.rel_path);
48669 buffer_free(d.path);
48670 buffer_free(d.rel_path);
48676 @@ -748,12 +841,12 @@
48677 if (S_ISDIR(sce->st.st_mode)) {
48678 buffer_append_string(b, "<D:getcontenttype>httpd/unix-directory</D:getcontenttype>");
48680 - } else if(S_ISREG(sce->st.st_mode)) {
48681 + } else if(S_ISREG(sce->st.st_mode)) {
48682 for (k = 0; k < con->conf.mimetypes->used; k++) {
48683 data_string *ds = (data_string *)con->conf.mimetypes->data[k];
48686 if (ds->key->used == 0) continue;
48689 if (buffer_is_equal_right_len(dst->path, ds->key, ds->key->used - 1)) {
48690 buffer_append_string(b,"<D:getcontenttype>");
48691 buffer_append_string_buffer(b, ds->value);
48692 @@ -807,23 +900,23 @@
48694 /* bind the values to the insert */
48696 - sqlite3_bind_text(stmt, 1,
48697 - dst->rel_path->ptr,
48698 + sqlite3_bind_text(stmt, 1,
48699 + dst->rel_path->ptr,
48700 dst->rel_path->used - 1,
48702 - sqlite3_bind_text(stmt, 2,
48703 + sqlite3_bind_text(stmt, 2,
48707 - sqlite3_bind_text(stmt, 3,
48708 + sqlite3_bind_text(stmt, 3,
48714 - while (SQLITE_ROW == sqlite3_step(p->conf.stmt_select_prop)) {
48715 + while (SQLITE_ROW == sqlite3_step(stmt)) {
48716 /* there is a row for us, we only expect a single col 'value' */
48717 - webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(p->conf.stmt_select_prop, 0), b);
48718 + webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(stmt, 0), b);
48722 @@ -840,7 +933,7 @@
48726 -webdav_property live_properties[] = {
48727 +webdav_property live_properties[] = {
48728 { "DAV:", "creationdate" },
48729 { "DAV:", "displayname" },
48730 { "DAV:", "getcontentlanguage" },
48731 @@ -871,8 +964,8 @@
48732 webdav_property *prop;
48734 prop = props->ptr[i];
48736 - if (0 != webdav_get_property(srv, con, p,
48738 + if (0 != webdav_get_property(srv, con, p,
48739 dst, prop->prop, prop->ns, b_200)) {
48740 webdav_gen_prop_tag(srv, con, prop->prop, prop->ns, NULL, b_404);
48742 @@ -916,12 +1009,12 @@
48743 if (-1 == c->file.fd && /* open the file if not already open */
48744 -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
48745 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
48752 if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
48753 - log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
48754 + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
48755 strerror(errno), c->file.name, c->file.fd);
48758 @@ -938,7 +1031,7 @@
48759 if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->file.mmap.start + c->offset, weHave, 0))) {
48760 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
48764 c->offset += weHave;
48765 cq->bytes_out += weHave;
48767 @@ -956,7 +1049,7 @@
48768 if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->mem->ptr + c->offset, weHave, 0))) {
48769 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
48773 c->offset += weHave;
48774 cq->bytes_out += weHave;
48776 @@ -991,6 +1084,113 @@
48780 +int webdav_lockdiscovery(server *srv, connection *con,
48781 + buffer *locktoken, const char *lockscope, const char *locktype, int depth) {
48785 + response_header_overwrite(srv, con, CONST_STR_LEN("Lock-Token"), CONST_BUF_LEN(locktoken));
48787 + response_header_overwrite(srv, con,
48788 + CONST_STR_LEN("Content-Type"),
48789 + CONST_STR_LEN("text/xml; charset=\"utf-8\""));
48791 + b = chunkqueue_get_append_buffer(con->send);
48793 + buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
48795 + buffer_append_string(b,"<D:prop xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
48796 + buffer_append_string(b,"<D:lockdiscovery>\n");
48797 + buffer_append_string(b,"<D:activelock>\n");
48799 + buffer_append_string(b,"<D:lockscope>");
48800 + buffer_append_string(b,"<D:");
48801 + buffer_append_string(b, lockscope);
48802 + buffer_append_string(b, "/>");
48803 + buffer_append_string(b,"</D:lockscope>\n");
48805 + buffer_append_string(b,"<D:locktype>");
48806 + buffer_append_string(b,"<D:");
48807 + buffer_append_string(b, locktype);
48808 + buffer_append_string(b, "/>");
48809 + buffer_append_string(b,"</D:locktype>\n");
48811 + buffer_append_string(b,"<D:depth>");
48812 + buffer_append_string(b, depth == 0 ? "0" : "infinity");
48813 + buffer_append_string(b,"</D:depth>\n");
48815 + buffer_append_string(b,"<D:timeout>");
48816 + buffer_append_string(b, "Second-600");
48817 + buffer_append_string(b,"</D:timeout>\n");
48819 + buffer_append_string(b,"<D:owner>");
48820 + buffer_append_string(b,"</D:owner>\n");
48822 + buffer_append_string(b,"<D:locktoken>");
48823 + buffer_append_string(b, "<D:href>");
48824 + buffer_append_string_buffer(b, locktoken);
48825 + buffer_append_string(b, "</D:href>");
48826 + buffer_append_string(b,"</D:locktoken>\n");
48828 + buffer_append_string(b,"</D:activelock>\n");
48829 + buffer_append_string(b,"</D:lockdiscovery>\n");
48830 + buffer_append_string(b,"</D:prop>\n");
48835 + * check if resource is having the right locks to access to resource
48840 +int webdav_has_lock(server *srv, connection *con, plugin_data *p, buffer *uri) {
48841 + int has_lock = 1;
48851 + * there is NOT, AND and OR
48852 + * and a list can be tagged
48854 + * (<lock-token>) is untagged
48855 + * <tag> (<lock-token>) is tagged
48857 + * as long as we don't handle collections it is simple. :)
48859 + * X-Litmus: locks: 11 (owner_modify)
48860 + * If: <http://127.0.0.1:1025/dav/litmus/lockme> (<opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1>)
48862 + * X-Litmus: locks: 16 (fail_cond_put)
48863 + * If: (<DAV:no-lock> ["-1622396671"])
48865 + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
48867 + /* we didn't provided a lock-token -> */
48868 + /* if the resource is locked -> 423 */
48870 + sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
48872 + sqlite3_reset(stmt);
48874 + sqlite3_bind_text(stmt, 1,
48875 + CONST_BUF_LEN(uri),
48876 + SQLITE_TRANSIENT);
48878 + while (SQLITE_ROW == sqlite3_step(stmt)) {
48887 URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
48888 plugin_data *p = p_d;
48890 @@ -1001,7 +1201,8 @@
48893 webdav_properties *req_props;
48895 + stat_cache_entry *sce = NULL;
48899 if (!p->conf.enabled) return HANDLER_GO_ON;
48900 @@ -1019,13 +1220,25 @@
48903 /* is there a content-body ? */
48906 + switch (stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
48907 + case HANDLER_ERROR:
48908 + if (errno == ENOENT) {
48909 + con->http_status = 404;
48910 + return HANDLER_FINISHED;
48918 #ifdef USE_PROPPATCH
48919 /* any special requests or just allprop ? */
48920 if (con->request.content_length) {
48923 - if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
48924 + if (1 == webdav_parse_chunkqueue(srv, con, p, con->recv, &xml)) {
48925 xmlNode *rootnode = xmlDocGetRootElement(xml);
48928 @@ -1087,14 +1300,13 @@
48929 /* get all property names (EMPTY) */
48930 sqlite3_reset(stmt);
48931 /* bind the values to the insert */
48933 - sqlite3_bind_text(stmt, 1,
48934 - con->uri.path->ptr,
48936 + sqlite3_bind_text(stmt, 1,
48937 + con->uri.path->ptr,
48938 con->uri.path->used - 1,
48942 if (SQLITE_DONE != sqlite3_step(stmt)) {
48946 } else if (0 == xmlStrcmp(cmd->name, BAD_CAST "allprop")) {
48947 @@ -1114,14 +1326,14 @@
48949 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
48951 - b = chunkqueue_get_append_buffer(con->write_queue);
48953 + b = chunkqueue_get_append_buffer(con->send);
48955 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
48957 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
48962 prop_200 = buffer_init();
48963 prop_404 = buffer_init();
48965 @@ -1129,7 +1341,7 @@
48968 webdav_get_props(srv, con, p, &(con->physical), req_props, prop_200, prop_404);
48971 buffer_append_string(b,"<D:response>\n");
48972 buffer_append_string(b,"<D:href>");
48973 buffer_append_string_buffer(b, con->uri.scheme);
48974 @@ -1145,9 +1357,9 @@
48975 buffer_append_string_buffer(b, prop_200);
48977 buffer_append_string(b,"</D:prop>\n");
48980 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
48983 buffer_append_string(b,"</D:propstat>\n");
48985 if (!buffer_is_empty(prop_404)) {
48986 @@ -1157,16 +1369,16 @@
48987 buffer_append_string_buffer(b, prop_404);
48989 buffer_append_string(b,"</D:prop>\n");
48992 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
48995 buffer_append_string(b,"</D:propstat>\n");
48998 buffer_append_string(b,"</D:response>\n");
49003 if (NULL != (dir = opendir(con->physical.path->ptr))) {
49006 @@ -1179,16 +1391,16 @@
49007 if (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0') {
49009 /* ignore the parent dir */
49013 buffer_copy_string_buffer(d.path, dst->path);
49014 - BUFFER_APPEND_SLASH(d.path);
49015 + PATHNAME_APPEND_SLASH(d.path);
49017 buffer_copy_string_buffer(d.rel_path, dst->rel_path);
49018 - BUFFER_APPEND_SLASH(d.rel_path);
49019 + PATHNAME_APPEND_SLASH(d.rel_path);
49021 if (de->d_name[0] == '.' && de->d_name[1] == '\0') {
49022 - /* don't append the . */
49023 + /* don't append the . */
49025 buffer_append_string(d.path, de->d_name);
49026 buffer_append_string(d.rel_path, de->d_name);
49027 @@ -1198,7 +1410,7 @@
49028 buffer_reset(prop_404);
49030 webdav_get_props(srv, con, p, &d, req_props, prop_200, prop_404);
49033 buffer_append_string(b,"<D:response>\n");
49034 buffer_append_string(b,"<D:href>");
49035 buffer_append_string_buffer(b, con->uri.scheme);
49036 @@ -1214,9 +1426,9 @@
49037 buffer_append_string_buffer(b, prop_200);
49039 buffer_append_string(b,"</D:prop>\n");
49042 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
49045 buffer_append_string(b,"</D:propstat>\n");
49047 if (!buffer_is_empty(prop_404)) {
49048 @@ -1226,9 +1438,9 @@
49049 buffer_append_string_buffer(b, prop_404);
49051 buffer_append_string(b,"</D:prop>\n");
49054 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
49057 buffer_append_string(b,"</D:propstat>\n");
49060 @@ -1260,7 +1472,7 @@
49061 if (p->conf.log_xml) {
49062 log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
49064 - con->file_finished = 1;
49065 + con->send->is_closed = 1;
49067 return HANDLER_FINISHED;
49068 case HTTP_METHOD_MKCOL:
49069 @@ -1275,7 +1487,7 @@
49071 return HANDLER_FINISHED;
49075 /* let's create the directory */
49077 if (-1 == mkdir(con->physical.path->ptr, 0700)) {
49078 @@ -1294,7 +1506,7 @@
49081 con->http_status = 201;
49082 - con->file_finished = 1;
49083 + con->send->is_closed = 1;
49086 return HANDLER_FINISHED;
49087 @@ -1303,7 +1515,13 @@
49088 con->http_status = 403;
49089 return HANDLER_FINISHED;
49093 + /* does the client have a lock for this connection ? */
49094 + if (!webdav_has_lock(srv, con, p, con->uri.path)) {
49095 + con->http_status = 423;
49096 + return HANDLER_FINISHED;
49099 /* stat and unlink afterwards */
49100 if (-1 == stat(con->physical.path->ptr, &st)) {
49101 /* don't about it yet, unlink will fail too */
49102 @@ -1322,8 +1540,8 @@
49103 /* we got an error somewhere in between, build a 207 */
49104 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
49106 - b = chunkqueue_get_append_buffer(con->write_queue);
49108 + b = chunkqueue_get_append_buffer(con->send);
49110 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
49112 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\">\n");
49113 @@ -1331,16 +1549,16 @@
49114 buffer_append_string_buffer(b, multi_status_resp);
49116 buffer_append_string(b,"</D:multistatus>\n");
49119 if (p->conf.log_xml) {
49120 log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
49123 con->http_status = 207;
49124 - con->file_finished = 1;
49125 + con->send->is_closed = 1;
49127 /* everything went fine, remove the directory */
49130 if (-1 == rmdir(con->physical.path->ptr)) {
49133 @@ -1374,98 +1592,175 @@
49134 return HANDLER_FINISHED;
49135 case HTTP_METHOD_PUT: {
49137 - chunkqueue *cq = con->request_content_queue;
49138 + chunkqueue *cq = con->recv;
49140 + data_string *ds_range;
49142 if (p->conf.is_readonly) {
49143 con->http_status = 403;
49144 return HANDLER_FINISHED;
49147 + /* is a exclusive lock set on the source */
49148 + if (!webdav_has_lock(srv, con, p, con->uri.path)) {
49149 + con->http_status = 423;
49150 + return HANDLER_FINISHED;
49154 assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
49156 - /* taken what we have in the request-body and write it to a file */
49157 - if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC, 0600))) {
49158 - /* we can't open the file */
49159 - con->http_status = 403;
49162 + /* RFC2616 Section 9.6 PUT requires us to send 501 on all Content-* we don't support
49163 + * - most important Content-Range
49166 + * Example: Content-Range: bytes 100-1037/1038 */
49168 - con->http_status = 201; /* created */
49169 - con->file_finished = 1;
49170 + if (NULL != (ds_range = (data_string *)array_get_element(con->request.headers, "Content-Range"))) {
49171 + const char *num = ds_range->value->ptr;
49173 + char *err = NULL;
49175 - for (c = cq->first; c; c = cq->first) {
49177 + if (0 != strncmp(num, "bytes ", 6)) {
49178 + con->http_status = 501; /* not implemented */
49180 - /* copy all chunks */
49181 - switch(c->type) {
49184 - if (c->file.mmap.start == MAP_FAILED) {
49185 - if (-1 == c->file.fd && /* open the file if not already open */
49186 - -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
49187 - log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
49192 - if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
49193 - log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
49194 - strerror(errno), c->file.name, c->file.fd);
49195 + return HANDLER_FINISHED;
49200 + /* we only support <num>- ... */
49202 - c->file.mmap.length = c->file.length;
49205 - close(c->file.fd);
49208 - /* chunk_reset() or chunk_free() will cleanup for us */
49211 - if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
49214 - con->http_status = 507;
49218 - con->http_status = 403;
49224 - if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
49227 - con->http_status = 507;
49231 - con->http_status = 403;
49236 + while (*num == ' ' || *num == '\t') num++;
49238 + if (*num == '\0') {
49239 + con->http_status = 501; /* not implemented */
49241 + return HANDLER_FINISHED;
49244 + offset = strtoll(num, &err, 10);
49246 + if (*err != '-' || offset < 0) {
49247 + con->http_status = 501; /* not implemented */
49249 + return HANDLER_FINISHED;
49252 + if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, 0600))) {
49255 + con->http_status = 404; /* not found */
49257 - case UNUSED_CHUNK:
49259 + con->http_status = 403; /* not found */
49262 + return HANDLER_FINISHED;
49265 + if (-1 == lseek(fd, offset, SEEK_SET)) {
49266 + con->http_status = 501; /* not implemented */
49270 + return HANDLER_FINISHED;
49272 + con->http_status = 200; /* modified */
49274 + /* take what we have in the request-body and write it to a file */
49278 - cq->bytes_out += r;
49279 + /* if the file doesn't exist, create it */
49280 + if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, 0600))) {
49281 + if (errno == ENOENT &&
49282 + -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0600))) {
49283 + /* we can't open the file */
49284 + con->http_status = 403;
49286 + return HANDLER_FINISHED;
49289 + con->http_status = 201; /* created */
49291 - chunkqueue_remove_finished_chunks(cq);
49293 + con->http_status = 200; /* modified */
49298 + con->send->is_closed = 1;
49300 + for (c = cq->first; c; c = cq->first) {
49303 + /* copy all chunks */
49304 + switch(c->type) {
49307 + if (c->file.mmap.start == MAP_FAILED) {
49308 + if (-1 == c->file.fd && /* open the file if not already open */
49309 + -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
49310 + log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
49315 + if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
49316 + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
49317 + strerror(errno), c->file.name, c->file.fd);
49322 + c->file.mmap.length = c->file.length;
49324 + close(c->file.fd);
49327 + /* chunk_reset() or chunk_free() will cleanup for us */
49330 + if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
49333 + con->http_status = 507;
49337 + con->http_status = 403;
49343 + if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
49346 + con->http_status = 507;
49350 + con->http_status = 403;
49355 + case UNUSED_CHUNK:
49361 + cq->bytes_out += r;
49365 + chunkqueue_remove_finished_chunks(cq);
49369 return HANDLER_FINISHED;
49371 - case HTTP_METHOD_MOVE:
49372 + case HTTP_METHOD_MOVE:
49373 case HTTP_METHOD_COPY: {
49374 buffer *destination = NULL;
49376 @@ -1475,7 +1770,15 @@
49377 con->http_status = 403;
49378 return HANDLER_FINISHED;
49382 + /* is a exclusive lock set on the source */
49383 + if (con->request.http_method == HTTP_METHOD_MOVE) {
49384 + if (!webdav_has_lock(srv, con, p, con->uri.path)) {
49385 + con->http_status = 423;
49386 + return HANDLER_FINISHED;
49390 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Destination"))) {
49391 destination = ds->value;
49393 @@ -1549,10 +1852,10 @@
49396 buffer_copy_string_buffer(p->physical.path, p->physical.doc_root);
49397 - BUFFER_APPEND_SLASH(p->physical.path);
49398 + PATHNAME_APPEND_SLASH(p->physical.path);
49399 buffer_copy_string_buffer(p->physical.basedir, p->physical.path);
49401 - /* don't add a second / */
49402 + /* don't add a second / */
49403 if (p->physical.rel_path->ptr[0] == '/') {
49404 buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr + 1, p->physical.rel_path->used - 2);
49406 @@ -1608,11 +1911,17 @@
49407 rmdir(con->physical.path->ptr);
49409 con->http_status = 201;
49410 - con->file_finished = 1;
49411 + con->send->is_closed = 1;
49413 /* it is just a file, good */
49416 + /* does the client have a lock for this connection ? */
49417 + if (!webdav_has_lock(srv, con, p, p->uri.path)) {
49418 + con->http_status = 423;
49419 + return HANDLER_FINISHED;
49422 /* destination exists */
49423 if (0 == (r = stat(p->physical.path->ptr, &st))) {
49424 if (S_ISDIR(st.st_mode)) {
49425 @@ -1628,7 +1937,7 @@
49428 con->http_status = 201; /* we will create a new one */
49429 - con->file_finished = 1;
49430 + con->send->is_closed = 1;
49434 @@ -1636,7 +1945,7 @@
49435 return HANDLER_FINISHED;
49437 } else if (overwrite == 0) {
49438 - /* destination exists, but overwrite is not set */
49439 + /* destination exists, but overwrite is not set */
49440 con->http_status = 412;
49441 return HANDLER_FINISHED;
49443 @@ -1655,16 +1964,16 @@
49444 sqlite3_reset(stmt);
49446 /* bind the values to the insert */
49447 - sqlite3_bind_text(stmt, 1,
49448 - p->uri.path->ptr,
49449 + sqlite3_bind_text(stmt, 1,
49450 + p->uri.path->ptr,
49451 p->uri.path->used - 1,
49454 - sqlite3_bind_text(stmt, 2,
49455 - con->uri.path->ptr,
49456 + sqlite3_bind_text(stmt, 2,
49457 + con->uri.path->ptr,
49458 con->uri.path->used - 1,
49462 if (SQLITE_DONE != sqlite3_step(stmt)) {
49463 log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move failed:", sqlite3_errmsg(p->conf.sql));
49465 @@ -1691,12 +2000,17 @@
49467 return HANDLER_FINISHED;
49469 - case HTTP_METHOD_PROPPATCH: {
49470 + case HTTP_METHOD_PROPPATCH:
49471 if (p->conf.is_readonly) {
49472 con->http_status = 403;
49473 return HANDLER_FINISHED;
49476 + if (!webdav_has_lock(srv, con, p, con->uri.path)) {
49477 + con->http_status = 423;
49478 + return HANDLER_FINISHED;
49481 /* check if destination exists */
49482 if (-1 == stat(con->physical.path->ptr, &st)) {
49484 @@ -1710,7 +2024,7 @@
49485 if (con->request.content_length) {
49488 - if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
49489 + if (1 == webdav_parse_chunkqueue(srv, con, p, con->recv, &xml)) {
49490 xmlNode *rootnode = xmlDocGetRootElement(xml);
49492 if (0 == xmlStrcmp(rootnode->name, BAD_CAST "propertyupdate")) {
49493 @@ -1737,7 +2051,7 @@
49495 sqlite3_stmt *stmt;
49497 - stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ?
49498 + stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ?
49499 p->conf.stmt_delete_prop : p->conf.stmt_update_prop;
49501 for (props = cmd->children; props; props = props->next) {
49502 @@ -1762,34 +2076,35 @@
49504 /* bind the values to the insert */
49506 - sqlite3_bind_text(stmt, 1,
49507 - con->uri.path->ptr,
49508 + sqlite3_bind_text(stmt, 1,
49509 + con->uri.path->ptr,
49510 con->uri.path->used - 1,
49512 - sqlite3_bind_text(stmt, 2,
49513 + sqlite3_bind_text(stmt, 2,
49514 (char *)prop->name,
49515 strlen((char *)prop->name),
49518 - sqlite3_bind_text(stmt, 3,
49519 + sqlite3_bind_text(stmt, 3,
49520 (char *)prop->ns->href,
49521 strlen((char *)prop->ns->href),
49524 - sqlite3_bind_text(stmt, 3,
49525 + sqlite3_bind_text(stmt, 3,
49530 if (stmt == p->conf.stmt_update_prop) {
49531 - sqlite3_bind_text(stmt, 4,
49532 + sqlite3_bind_text(stmt, 4,
49533 (char *)xmlNodeGetContent(prop),
49534 strlen((char *)xmlNodeGetContent(prop)),
49539 if (SQLITE_DONE != (r = sqlite3_step(stmt))) {
49540 - log_error_write(srv, __FILE__, __LINE__, "ss", "sql-set failed:", sqlite3_errmsg(p->conf.sql));
49541 + log_error_write(srv, __FILE__, __LINE__, "ss",
49542 + "sql-set failed:", sqlite3_errmsg(p->conf.sql));
49546 @@ -1804,7 +2119,7 @@
49548 goto propmatch_cleanup;
49552 con->http_status = 400;
49554 if (SQLITE_OK != sqlite3_exec(p->conf.sql, "COMMIT", NULL, NULL, &err)) {
49555 @@ -1815,12 +2130,13 @@
49557 con->http_status = 200;
49559 - con->file_finished = 1;
49560 + con->send->is_closed = 1;
49562 return HANDLER_FINISHED;
49569 con->http_status = 400;
49570 @@ -1830,11 +2146,307 @@
49572 con->http_status = 501;
49573 return HANDLER_FINISHED;
49575 + case HTTP_METHOD_LOCK:
49577 + * a mac wants to write
49579 + * LOCK /dav/expire.txt HTTP/1.1\r\n
49580 + * User-Agent: WebDAVFS/1.3 (01308000) Darwin/8.1.0 (Power Macintosh)\r\n
49581 + * Accept: * / *\r\n
49583 + * Timeout: Second-600\r\n
49584 + * Content-Type: text/xml; charset=\"utf-8\"\r\n
49585 + * Content-Length: 229\r\n
49586 + * Connection: keep-alive\r\n
49587 + * Host: 192.168.178.23:1025\r\n
49589 + * <?xml version=\"1.0\" encoding=\"utf-8\"?>\n
49590 + * <D:lockinfo xmlns:D=\"DAV:\">\n
49591 + * <D:lockscope><D:exclusive/></D:lockscope>\n
49592 + * <D:locktype><D:write/></D:locktype>\n
49594 + * <D:href>http://www.apple.com/webdav_fs/</D:href>\n
49596 + * </D:lockinfo>\n
49599 + if (depth != 0 && depth != -1) {
49600 + con->http_status = 400;
49602 + return HANDLER_FINISHED;
49606 + if (con->request.content_length) {
49608 + buffer *hdr_if = NULL;
49610 + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
49611 + hdr_if = ds->value;
49614 + /* we don't support Depth: Infinity on locks */
49615 + if (hdr_if == NULL && depth == -1) {
49616 + con->http_status = 409; /* Conflict */
49618 + return HANDLER_FINISHED;
49621 + if (1 == webdav_parse_chunkqueue(srv, con, p, con->recv, &xml)) {
49622 + xmlNode *rootnode = xmlDocGetRootElement(xml);
49624 + assert(rootnode);
49626 + if (0 == xmlStrcmp(rootnode->name, BAD_CAST "lockinfo")) {
49627 + xmlNode *lockinfo;
49628 + const xmlChar *lockscope = NULL, *locktype = NULL, *owner = NULL;
49630 + for (lockinfo = rootnode->children; lockinfo; lockinfo = lockinfo->next) {
49631 + if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "lockscope")) {
49633 + for (value = lockinfo->children; value; value = value->next) {
49634 + if ((0 == xmlStrcmp(value->name, BAD_CAST "exclusive")) ||
49635 + (0 == xmlStrcmp(value->name, BAD_CAST "shared"))) {
49636 + lockscope = value->name;
49638 + con->http_status = 400;
49641 + return HANDLER_FINISHED;
49644 + } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "locktype")) {
49646 + for (value = lockinfo->children; value; value = value->next) {
49647 + if ((0 == xmlStrcmp(value->name, BAD_CAST "write"))) {
49648 + locktype = value->name;
49650 + con->http_status = 400;
49653 + return HANDLER_FINISHED;
49657 + } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "owner")) {
49661 + if (lockscope && locktype) {
49662 + sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
49664 + /* is this resourse already locked ? */
49666 + /* SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout
49668 + * WHERE resource = ? */
49672 + sqlite3_reset(stmt);
49674 + sqlite3_bind_text(stmt, 1,
49675 + p->uri.path->ptr,
49676 + p->uri.path->used - 1,
49677 + SQLITE_TRANSIENT);
49679 + /* it is the PK */
49680 + while (SQLITE_ROW == sqlite3_step(stmt)) {
49681 + /* we found a lock
49682 + * 1. is it compatible ?
49683 + * 2. is it ours */
49684 + char *sql_lockscope = (char *)sqlite3_column_text(stmt, 2);
49686 + if (strcmp(sql_lockscope, "exclusive")) {
49687 + con->http_status = 423;
49688 + } else if (0 == xmlStrcmp(lockscope, BAD_CAST "exclusive")) {
49689 + /* resourse is locked with a shared lock
49690 + * client wants exclusive */
49691 + con->http_status = 423;
49694 + if (con->http_status == 423) {
49696 + return HANDLER_FINISHED;
49700 + stmt = p->conf.stmt_create_lock;
49702 + /* create a lock-token */
49704 + char uuid[37] /* 36 + \0 */;
49706 + uuid_generate(id);
49707 + uuid_unparse(id, uuid);
49709 + buffer_copy_string(p->tmp_buf, "opaquelocktoken:");
49710 + buffer_append_string(p->tmp_buf, uuid);
49712 + /* "CREATE TABLE locks ("
49713 + * " locktoken TEXT NOT NULL,"
49714 + * " resource TEXT NOT NULL,"
49715 + * " lockscope TEXT NOT NULL,"
49716 + * " locktype TEXT NOT NULL,"
49717 + * " owner TEXT NOT NULL,"
49718 + * " depth INT NOT NULL,"
49721 + sqlite3_reset(stmt);
49723 + sqlite3_bind_text(stmt, 1,
49724 + CONST_BUF_LEN(p->tmp_buf),
49725 + SQLITE_TRANSIENT);
49727 + sqlite3_bind_text(stmt, 2,
49728 + CONST_BUF_LEN(con->uri.path),
49729 + SQLITE_TRANSIENT);
49731 + sqlite3_bind_text(stmt, 3,
49733 + xmlStrlen(lockscope),
49734 + SQLITE_TRANSIENT);
49736 + sqlite3_bind_text(stmt, 4,
49738 + xmlStrlen(locktype),
49739 + SQLITE_TRANSIENT);
49742 + sqlite3_bind_text(stmt, 5,
49745 + SQLITE_TRANSIENT);
49748 + sqlite3_bind_int(stmt, 6,
49752 + if (SQLITE_DONE != sqlite3_step(stmt)) {
49753 + log_error_write(srv, __FILE__, __LINE__, "ss",
49754 + "create lock:", sqlite3_errmsg(p->conf.sql));
49757 + /* looks like we survived */
49758 + webdav_lockdiscovery(srv, con, p->tmp_buf, lockscope, locktype, depth);
49760 + con->http_status = 201;
49761 + con->send->is_closed = 1;
49767 + return HANDLER_FINISHED;
49769 + con->http_status = 400;
49770 + return HANDLER_FINISHED;
49774 + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
49775 + buffer *locktoken = ds->value;
49776 + sqlite3_stmt *stmt = p->conf.stmt_refresh_lock;
49778 + /* remove the < > around the token */
49779 + if (locktoken->used < 6) {
49780 + con->http_status = 400;
49782 + return HANDLER_FINISHED;
49785 + buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 2, locktoken->used - 5);
49787 + sqlite3_reset(stmt);
49789 + sqlite3_bind_text(stmt, 1,
49790 + CONST_BUF_LEN(p->tmp_buf),
49791 + SQLITE_TRANSIENT);
49793 + if (SQLITE_DONE != sqlite3_step(stmt)) {
49794 + log_error_write(srv, __FILE__, __LINE__, "ss",
49795 + "refresh lock:", sqlite3_errmsg(p->conf.sql));
49798 + webdav_lockdiscovery(srv, con, p->tmp_buf, "exclusive", "write", 0);
49800 + con->http_status = 200;
49801 + con->send->is_closed = 1;
49802 + return HANDLER_FINISHED;
49804 + /* we need a lock-token to refresh */
49805 + con->http_status = 400;
49807 + return HANDLER_FINISHED;
49812 + con->http_status = 501;
49813 + return HANDLER_FINISHED;
49815 + case HTTP_METHOD_UNLOCK:
49817 + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Lock-Token"))) {
49818 + buffer *locktoken = ds->value;
49819 + sqlite3_stmt *stmt = p->conf.stmt_remove_lock;
49821 + /* remove the < > around the token */
49822 + if (locktoken->used < 4) {
49823 + con->http_status = 400;
49825 + return HANDLER_FINISHED;
49831 + * if the resourse is locked:
49832 + * - by us: unlock
49833 + * - by someone else: 401
49834 + * if the resource is not locked:
49838 + buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 1, locktoken->used - 3);
49840 + sqlite3_reset(stmt);
49842 + sqlite3_bind_text(stmt, 1,
49843 + CONST_BUF_LEN(p->tmp_buf),
49844 + SQLITE_TRANSIENT);
49846 + sqlite3_bind_text(stmt, 2,
49847 + CONST_BUF_LEN(con->uri.path),
49848 + SQLITE_TRANSIENT);
49850 + if (SQLITE_DONE != sqlite3_step(stmt)) {
49851 + log_error_write(srv, __FILE__, __LINE__, "ss",
49852 + "remove lock:", sqlite3_errmsg(p->conf.sql));
49855 + if (0 == sqlite3_changes(p->conf.sql)) {
49856 + con->http_status = 401;
49858 + con->http_status = 204;
49860 + return HANDLER_FINISHED;
49862 + /* we need a lock-token to unlock */
49863 + con->http_status = 400;
49865 + return HANDLER_FINISHED;
49869 + con->http_status = 501;
49870 + return HANDLER_FINISHED;
49878 return HANDLER_GO_ON;
49880 @@ -1845,14 +2457,14 @@
49881 int mod_webdav_plugin_init(plugin *p) {
49882 p->version = LIGHTTPD_VERSION_ID;
49883 p->name = buffer_init_string("webdav");
49886 p->init = mod_webdav_init;
49887 p->handle_uri_clean = mod_webdav_uri_handler;
49888 p->handle_physical = mod_webdav_subrequest_handler;
49889 p->set_defaults = mod_webdav_set_defaults;
49890 p->cleanup = mod_webdav_free;
49898 --- ../lighttpd-1.4.11/src/network.c 2006-03-04 16:45:46.000000000 +0200
49899 +++ lighttpd-1.5.0/src/network.c 2006-09-07 00:57:05.000000000 +0300
49901 #include <sys/types.h>
49902 #include <sys/stat.h>
49903 -#include <sys/time.h>
49907 -#include <unistd.h>
49908 #include <string.h>
49909 #include <stdlib.h>
49910 #include <assert.h>
49912 +#include <stdio.h>
49914 #include "network.h"
49915 #include "fdevent.h"
49917 @@ -19,11 +19,12 @@
49918 #include "network_backends.h"
49919 #include "sys-mmap.h"
49920 #include "sys-socket.h"
49921 +#include "sys-files.h"
49924 -# include <openssl/ssl.h>
49925 -# include <openssl/err.h>
49926 -# include <openssl/rand.h>
49927 +# include <openssl/ssl.h>
49928 +# include <openssl/err.h>
49929 +# include <openssl/rand.h>
49932 handler_t network_server_handle_fdevent(void *s, void *context, int revents) {
49933 @@ -31,25 +32,25 @@
49934 server_socket *srv_socket = (server_socket *)context;
49942 if (revents != FDEVENT_IN) {
49943 - log_error_write(srv, __FILE__, __LINE__, "sdd",
49944 + log_error_write(srv, __FILE__, __LINE__, "sdd",
49945 "strange event for server socket",
49947 + srv_socket->sock->fd,
49949 return HANDLER_ERROR;
49952 /* accept()s at most 100 connections directly
49954 - * we jump out after 100 to give the waiting connections a chance */
49955 + * we jump out after 100 to give the waiting connections a chance */
49956 for (loops = 0; loops < 100 && NULL != (con = connection_accept(srv, srv_socket)); loops++) {
49960 connection_state_machine(srv, con);
49963 switch(r = plugins_call_handle_joblist(srv, con)) {
49964 case HANDLER_FINISHED:
49965 case HANDLER_GO_ON:
49966 @@ -72,18 +73,18 @@
49968 int is_unix_domain_socket = 0;
49972 #ifdef SO_ACCEPTFILTER
49973 struct accept_filter_arg afa;
49978 WORD wVersionRequested;
49983 wVersionRequested = MAKEWORD( 2, 2 );
49986 err = WSAStartup( wVersionRequested, &wsaData );
49988 /* Tell the user that we could not find a usable */
49989 @@ -91,37 +92,37 @@
49995 srv_socket = calloc(1, sizeof(*srv_socket));
49996 - srv_socket->fd = -1;
49998 + srv_socket->sock = iosocket_init();
50000 srv_socket->srv_token = buffer_init();
50001 buffer_copy_string_buffer(srv_socket->srv_token, host_token);
50005 buffer_copy_string_buffer(b, host_token);
50012 if (NULL == (sp = strrchr(b->ptr, ':'))) {
50013 log_error_write(srv, __FILE__, __LINE__, "sb", "value of $SERVER[\"socket\"] has to be \"ip:port\".", b);
50023 /* check for [ and ] */
50024 if (b->ptr[0] == '[' && *(sp-1) == ']') {
50036 port = strtol(sp, NULL, 10);
50038 if (host[0] == '/') {
50039 @@ -129,18 +130,18 @@
50040 is_unix_domain_socket = 1;
50041 } else if (port == 0 || port > 65535) {
50042 log_error_write(srv, __FILE__, __LINE__, "sd", "port out of range:", port);
50049 if (*host == '\0') host = NULL;
50051 if (is_unix_domain_socket) {
50052 #ifdef HAVE_SYS_UN_H
50054 srv_socket->addr.plain.sa_family = AF_UNIX;
50056 - if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
50058 + if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
50059 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
50062 @@ -154,32 +155,32 @@
50065 srv_socket->addr.plain.sa_family = AF_INET6;
50067 - if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
50069 + if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
50070 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
50073 srv_socket->use_ipv6 = 1;
50077 - if (srv_socket->fd == -1) {
50079 + if (srv_socket->sock->fd == -1) {
50080 srv_socket->addr.plain.sa_family = AF_INET;
50081 - if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
50082 + if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
50083 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
50090 - srv->cur_fds = srv_socket->fd;
50092 + srv->cur_fds = srv_socket->sock->fd;
50095 - if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
50096 + if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
50097 log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt failed:", strerror(errno));
50102 switch(srv_socket->addr.plain.sa_family) {
50105 @@ -190,23 +191,23 @@
50107 struct addrinfo hints, *res;
50111 memset(&hints, 0, sizeof(hints));
50114 hints.ai_family = AF_INET6;
50115 hints.ai_socktype = SOCK_STREAM;
50116 hints.ai_protocol = IPPROTO_TCP;
50119 if (0 != (r = getaddrinfo(host, NULL, &hints, &res))) {
50120 - log_error_write(srv, __FILE__, __LINE__,
50121 - "sssss", "getaddrinfo failed: ",
50122 + log_error_write(srv, __FILE__, __LINE__,
50123 + "sssss", "getaddrinfo failed: ",
50124 gai_strerror(r), "'", host, "'");
50131 memcpy(&(srv_socket->addr), res->ai_addr, res->ai_addrlen);
50136 srv_socket->addr.ipv6.sin6_port = htons(port);
50137 @@ -221,33 +222,34 @@
50139 struct hostent *he;
50140 if (NULL == (he = gethostbyname(host))) {
50141 - log_error_write(srv, __FILE__, __LINE__,
50142 - "sds", "gethostbyname failed: ",
50143 + log_error_write(srv, __FILE__, __LINE__,
50144 + "sds", "gethostbyname failed: ",
50150 if (he->h_addrtype != AF_INET) {
50151 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
50156 if (he->h_length != sizeof(struct in_addr)) {
50157 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
50162 memcpy(&(srv_socket->addr.ipv4.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
50164 srv_socket->addr.ipv4.sin_port = htons(port);
50167 addr_len = sizeof(struct sockaddr_in);
50173 srv_socket->addr.un.sun_family = AF_UNIX;
50174 strcpy(srv_socket->addr.un.sun_path, host);
50178 addr_len = SUN_LEN(&srv_socket->addr.un);
50180 @@ -256,11 +258,11 @@
50183 /* check if the socket exists and try to connect to it. */
50184 - if (-1 != (fd = connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
50185 + if (-1 != (fd = connect(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
50188 - log_error_write(srv, __FILE__, __LINE__, "ss",
50189 - "server socket is still in use:",
50190 + log_error_write(srv, __FILE__, __LINE__, "ss",
50191 + "server socket is still in use:",
50195 @@ -275,88 +277,89 @@
50199 - log_error_write(srv, __FILE__, __LINE__, "sds",
50200 - "testing socket failed:",
50201 + log_error_write(srv, __FILE__, __LINE__, "sds",
50202 + "testing socket failed:",
50203 host, strerror(errno));
50217 - if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
50219 + if (0 != bind(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
50220 switch(srv_socket->addr.plain.sa_family) {
50222 - log_error_write(srv, __FILE__, __LINE__, "sds",
50223 - "can't bind to socket:",
50224 + log_error_write(srv, __FILE__, __LINE__, "sds",
50225 + "can't bind to socket:",
50226 host, strerror(errno));
50229 - log_error_write(srv, __FILE__, __LINE__, "ssds",
50230 - "can't bind to port:",
50231 + log_error_write(srv, __FILE__, __LINE__, "ssds",
50232 + "can't bind to port:",
50233 host, port, strerror(errno));
50239 - if (-1 == listen(srv_socket->fd, 128 * 8)) {
50241 + if (-1 == listen(srv_socket->sock->fd, 128 * 8)) {
50242 log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));
50249 if (srv->ssl_is_init == 0) {
50250 SSL_load_error_strings();
50251 SSL_library_init();
50252 srv->ssl_is_init = 1;
50255 if (0 == RAND_status()) {
50256 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
50257 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
50258 "not enough entropy in the pool");
50264 if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
50265 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
50266 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
50267 ERR_error_string(ERR_get_error(), NULL));
50272 if (buffer_is_empty(s->ssl_pemfile)) {
50273 log_error_write(srv, __FILE__, __LINE__, "s", "ssl.pemfile has to be set");
50278 if (!buffer_is_empty(s->ssl_ca_file)) {
50279 if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {
50280 - log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
50281 + log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
50282 ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
50288 if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
50289 - log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
50290 + log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
50291 ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
50296 if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
50297 - log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
50298 + log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
50299 ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
50304 if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
50305 - log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
50306 + log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
50307 "Private key does not match the certificate public key, reason:",
50308 ERR_error_string(ERR_get_error(), NULL),
50310 @@ -364,15 +367,15 @@
50312 srv_socket->ssl_ctx = s->ssl_ctx;
50316 buffer_free(srv_socket->srv_token);
50322 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
50324 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
50325 "ssl requested but openssl support is not compiled in");
50331 @@ -383,17 +386,16 @@
50333 memset(&afa, 0, sizeof(afa));
50334 strcpy(afa.af_name, "httpready");
50335 - if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
50336 + if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
50337 if (errno != ENOENT) {
50338 log_error_write(srv, __FILE__, __LINE__, "ss", "can't set accept-filter 'httpready': ", strerror(errno));
50345 srv_socket->is_ssl = s->is_ssl;
50346 - srv_socket->fde_ndx = -1;
50349 if (srv->srv_sockets.size == 0) {
50350 srv->srv_sockets.size = 4;
50351 srv->srv_sockets.used = 0;
50352 @@ -402,11 +404,10 @@
50353 srv->srv_sockets.size += 4;
50354 srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket));
50358 srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
50366 @@ -414,45 +415,60 @@
50368 for (i = 0; i < srv->srv_sockets.used; i++) {
50369 server_socket *srv_socket = srv->srv_sockets.ptr[i];
50371 - if (srv_socket->fd != -1) {
50373 + if (srv_socket->sock->fd != -1) {
50374 /* check if server fd are already registered */
50375 - if (srv_socket->fde_ndx != -1) {
50376 - fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
50377 - fdevent_unregister(srv->ev, srv_socket->fd);
50378 + if (srv_socket->sock->fde_ndx != -1) {
50379 + fdevent_event_del(srv->ev, srv_socket->sock);
50380 + fdevent_unregister(srv->ev, srv_socket->sock);
50383 - close(srv_socket->fd);
50385 + closesocket(srv_socket->sock->fd);
50388 + if (srv_socket->is_ssl) {
50389 +#ifdef USE_OPENSSL
50390 + SSL_CTX_free(srv_socket->ssl_ctx);
50395 + iosocket_free(srv_socket->sock);
50397 buffer_free(srv_socket->srv_token);
50404 +#ifdef USE_OPENSSL
50405 + ERR_free_strings();
50407 free(srv->srv_sockets.ptr);
50414 NETWORK_BACKEND_UNSET,
50416 NETWORK_BACKEND_WRITE,
50417 NETWORK_BACKEND_WRITEV,
50418 NETWORK_BACKEND_LINUX_SENDFILE,
50419 NETWORK_BACKEND_FREEBSD_SENDFILE,
50420 - NETWORK_BACKEND_SOLARIS_SENDFILEV
50421 + NETWORK_BACKEND_SOLARIS_SENDFILEV,
50423 + NETWORK_BACKEND_WIN32_SEND,
50424 + NETWORK_BACKEND_WIN32_TRANSMITFILE,
50425 } network_backend_t;
50427 int network_init(server *srv) {
50430 network_backend_t backend;
50433 - network_backend_t nb;
50434 - const char *name;
50435 - } network_backends[] = {
50438 + network_backend_t nb;
50439 + const char *name;
50440 + } network_backends[] = {
50441 /* lowest id wins */
50442 #if defined USE_LINUX_SENDFILE
50443 { NETWORK_BACKEND_LINUX_SENDFILE, "linux-sendfile" },
50444 @@ -466,21 +482,30 @@
50445 #if defined USE_WRITEV
50446 { NETWORK_BACKEND_WRITEV, "writev" },
50448 +#if defined USE_WRITE
50449 { NETWORK_BACKEND_WRITE, "write" },
50451 +#if defined USE_WIN32_TRANSMITFILE
50452 + { NETWORK_BACKEND_WIN32_TRANSMITFILE, "win32-transmitfile" },
50454 +#if defined USE_WIN32_SEND
50455 + { NETWORK_BACKEND_WIN32_SEND, "win32-send" },
50458 { NETWORK_BACKEND_UNSET, NULL }
50465 buffer_copy_string_buffer(b, srv->srvconf.bindhost);
50466 buffer_append_string(b, ":");
50467 buffer_append_long(b, srv->srvconf.port);
50470 if (0 != network_server_init(srv, b, srv->config_storage[0])) {
50477 srv->network_ssl_backend_write = network_write_chunkqueue_openssl;
50479 @@ -500,54 +525,80 @@
50480 if (NULL == network_backends[i].name) {
50481 /* we don't know it */
50483 - log_error_write(srv, __FILE__, __LINE__, "sb",
50484 - "server.network-backend has a unknown value:",
50485 + log_error_write(srv, __FILE__, __LINE__, "sb",
50486 + "server.network-backend has a unknown value:",
50487 srv->srvconf.network_backend);
50493 +#define SET_NETWORK_BACKEND(read, write) \
50494 + srv->network_backend_write = network_write_chunkqueue_##write;\
50495 + srv->network_backend_read = network_read_chunkqueue_##read
50497 +#define SET_NETWORK_BACKEND_SSL(read, write) \
50498 + srv->network_ssl_backend_write = network_write_chunkqueue_##write;\
50499 + srv->network_ssl_backend_read = network_read_chunkqueue_##read
50503 +#ifdef USE_WIN32_SEND
50504 + case NETWORK_BACKEND_WIN32_SEND:
50505 + SET_NETWORK_BACKEND(win32recv, win32send);
50507 +#ifdef USE_WIN32_TRANSMITFILE
50508 + case NETWORK_BACKEND_WIN32_TRANSMITFILE:
50509 + SET_NETWORK_BACKEND(win32recv, win32transmitfile);
50515 case NETWORK_BACKEND_WRITE:
50516 - srv->network_backend_write = network_write_chunkqueue_write;
50517 + SET_NETWORK_BACKEND(read, write);
50521 case NETWORK_BACKEND_WRITEV:
50522 - srv->network_backend_write = network_write_chunkqueue_writev;
50523 + SET_NETWORK_BACKEND(read, writev);
50526 #ifdef USE_LINUX_SENDFILE
50527 case NETWORK_BACKEND_LINUX_SENDFILE:
50528 - srv->network_backend_write = network_write_chunkqueue_linuxsendfile;
50529 + SET_NETWORK_BACKEND(read, linuxsendfile);
50532 #ifdef USE_FREEBSD_SENDFILE
50533 case NETWORK_BACKEND_FREEBSD_SENDFILE:
50534 - srv->network_backend_write = network_write_chunkqueue_freebsdsendfile;
50535 + SET_NETWORK_BACKEND(read, freebsdsendfile);
50538 #ifdef USE_SOLARIS_SENDFILEV
50539 case NETWORK_BACKEND_SOLARIS_SENDFILEV:
50540 - srv->network_backend_write = network_write_chunkqueue_solarissendfilev;
50541 + SET_NETWORK_BACKEND(read, solarissendfilev);
50548 +#ifdef USE_OPENSSL
50549 + SET_NETWORK_BACKEND_SSL(openssl, openssl);
50552 /* check for $SERVER["socket"] */
50553 for (i = 1; i < srv->config_context->used; i++) {
50554 data_config *dc = (data_config *)srv->config_context->data[i];
50555 specific_config *s = srv->config_storage[i];
50559 /* not our stage */
50560 if (COMP_SERVER_SOCKET != dc->comp) continue;
50563 if (dc->cond != CONFIG_COND_EQ) {
50564 log_error_write(srv, __FILE__, __LINE__, "s", "only == is allowed for $SERVER[\"socket\"].");
50570 @@ -558,36 +609,47 @@
50576 if (j == srv->srv_sockets.used) {
50577 if (0 != network_server_init(srv, dc->string, s)) return -1;
50585 int network_register_fdevents(server *srv) {
50588 if (-1 == fdevent_reset(srv->ev)) {
50592 /* register fdevents after reset */
50593 for (i = 0; i < srv->srv_sockets.used; i++) {
50594 server_socket *srv_socket = srv->srv_sockets.ptr[i];
50596 - fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
50597 - fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
50598 + fdevent_register(srv->ev, srv_socket->sock, network_server_handle_fdevent, srv_socket);
50599 + fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
50604 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
50606 +network_status_t network_read(server *srv, connection *con, iosocket *sock, chunkqueue *cq) {
50607 + server_socket *srv_socket = con->srv_socket;
50609 + if (srv_socket->is_ssl) {
50610 +#ifdef USE_OPENSSL
50611 + return srv->network_ssl_backend_read(srv, con, sock, cq);
50613 + return NETWORK_STATUS_FATAL_ERROR;
50616 + return srv->network_backend_read(srv, con, sock, cq);
50620 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
50621 + network_status_t ret = NETWORK_STATUS_UNSET;
50627 server_socket *srv_socket = con->srv_socket;
50628 @@ -600,37 +662,42 @@
50629 joblist_append(srv, con);
50635 written = cq->bytes_out;
50639 /* Linux: put a cork into the socket as we want to combine the write() calls
50640 * but only if we really have multiple chunks
50642 if (cq->first && cq->first->next) {
50644 - setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
50645 + setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
50650 if (srv_socket->is_ssl) {
50652 - ret = srv->network_ssl_backend_write(srv, con, con->ssl, cq);
50653 + ret = srv->network_ssl_backend_write(srv, con, con->sock, cq);
50656 - ret = srv->network_backend_write(srv, con, con->fd, cq);
50657 + ret = srv->network_backend_write(srv, con, con->sock, cq);
50663 + case NETWORK_STATUS_WAIT_FOR_EVENT:
50664 + case NETWORK_STATUS_SUCCESS:
50665 chunkqueue_remove_finished_chunks(cq);
50666 - ret = chunkqueue_is_empty(cq) ? 0 : 1;
50677 - setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
50678 + setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
50682 @@ -639,13 +706,13 @@
50683 con->bytes_written_cur_second += written;
50685 *(con->conf.global_bytes_per_second_cnt_ptr) += written;
50688 if (con->conf.kbytes_per_second &&
50689 (con->bytes_written_cur_second > con->conf.kbytes_per_second * 1024)) {
50690 /* we reached the traffic limit */
50692 con->traffic_limit_reached = 1;
50693 joblist_append(srv, con);
50698 --- ../lighttpd-1.4.11/src/network.h 2005-08-11 01:26:42.000000000 +0300
50699 +++ lighttpd-1.5.0/src/network.h 2006-09-07 00:57:05.000000000 +0300
50702 #include "server.h"
50704 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
50705 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
50706 +network_status_t network_read(server *srv, connection *con, iosocket *sock, chunkqueue *c);
50708 int network_init(server *srv);
50709 int network_close(server *srv);
50711 int network_register_fdevents(server *srv);
50712 +handler_t network_server_handle_fdevent(void *s, void *context, int revents);
50715 --- ../lighttpd-1.4.11/src/network_backends.h 2005-10-24 15:13:51.000000000 +0300
50716 +++ lighttpd-1.5.0/src/network_backends.h 2006-07-18 13:03:40.000000000 +0300
50717 @@ -43,16 +43,47 @@
50718 # define USE_AIX_SENDFILE
50722 +* unix can use read/write or recv/send on sockets
50723 +* win32 only recv/send
50726 +# define USE_WIN32_SEND
50727 +/* wait for async-io support
50728 +# define USE_WIN32_TRANSMITFILE
50731 +# define USE_WRITE
50735 +#include "network.h"
50737 +#define NETWORK_BACKEND_WRITE_CHUNK(x) \
50738 + network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq, chunk *c)
50740 +#define NETWORK_BACKEND_WRITE(x) \
50741 + network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
50742 +#define NETWORK_BACKEND_READ(x) \
50743 + network_status_t network_read_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
50745 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem);
50747 +NETWORK_BACKEND_WRITE(write);
50748 +NETWORK_BACKEND_WRITE(writev);
50749 +NETWORK_BACKEND_WRITE(linuxsendfile);
50750 +NETWORK_BACKEND_WRITE(freebsdsendfile);
50751 +NETWORK_BACKEND_WRITE(solarissendfilev);
50753 +NETWORK_BACKEND_WRITE(win32transmitfile);
50754 +NETWORK_BACKEND_WRITE(win32send);
50756 +NETWORK_BACKEND_READ(read);
50757 +NETWORK_BACKEND_READ(win32recv);
50759 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq);
50760 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq);
50761 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
50762 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
50763 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq);
50765 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq);
50766 +NETWORK_BACKEND_WRITE(openssl);
50767 +NETWORK_BACKEND_READ(openssl);
50771 --- ../lighttpd-1.4.11/src/network_freebsd_sendfile.c 2005-10-22 12:28:18.000000000 +0300
50772 +++ lighttpd-1.5.0/src/network_freebsd_sendfile.c 2006-09-07 00:57:05.000000000 +0300
50773 @@ -26,182 +26,115 @@
50776 # ifdef __FreeBSD__
50777 -/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
50778 +/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
50779 # define UIO_MAXIOV 1024
50783 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
50784 +NETWORK_BACKEND_WRITE(freebsdsendfile) {
50786 size_t chunks_written = 0;
50789 for(c = cq->first; c; c = c->next, chunks_written++) {
50791 int chunk_finished = 0;
50793 + network_status_t ret;
50796 - case MEM_CHUNK: {
50801 - size_t num_chunks, i;
50802 - struct iovec chunks[UIO_MAXIOV];
50804 - size_t num_bytes = 0;
50806 - /* we can't send more then SSIZE_MAX bytes in one chunk */
50808 - /* build writev list
50810 - * 1. limit: num_chunks < UIO_MAXIOV
50811 - * 2. limit: num_bytes < SSIZE_MAX
50813 - for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
50815 - for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
50816 - if (tc->mem->used == 0) {
50817 - chunks[i].iov_base = tc->mem->ptr;
50818 - chunks[i].iov_len = 0;
50820 - offset = tc->mem->ptr + tc->offset;
50821 - toSend = tc->mem->used - 1 - tc->offset;
50823 - chunks[i].iov_base = offset;
50825 - /* protect the return value of writev() */
50826 - if (toSend > SSIZE_MAX ||
50827 - num_bytes + toSend > SSIZE_MAX) {
50828 - chunks[i].iov_len = SSIZE_MAX - num_bytes;
50830 - num_chunks = i + 1;
50833 - chunks[i].iov_len = toSend;
50836 - num_bytes += toSend;
50840 - if ((r = writev(fd, chunks, num_chunks)) < 0) {
50850 - log_error_write(srv, __FILE__, __LINE__, "ssd",
50851 - "writev failed:", strerror(errno), fd);
50856 + ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
50861 - /* check which chunks have been written */
50862 - cq->bytes_out += r;
50864 - for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
50865 - if (r >= (ssize_t)chunks[i].iov_len) {
50867 - r -= chunks[i].iov_len;
50868 - tc->offset += chunks[i].iov_len;
50870 + /* check which chunks are finished now */
50871 + for (tc = c; tc; tc = tc->next) {
50872 + /* finished the chunk */
50873 + if (tc->offset == tc->mem->used - 1) {
50874 + /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
50875 if (chunk_finished) {
50876 - /* skip the chunks from further touches */
50877 - chunks_written++;
50880 - /* chunks_written + c = c->next is done in the for()*/
50881 - chunk_finished++;
50882 + chunk_finished = 1;
50885 - /* partially written */
50888 - chunk_finished = 0;
50895 + if (ret != NETWORK_STATUS_SUCCESS) {
50904 stat_cache_entry *sce = NULL;
50908 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
50909 log_error_write(srv, __FILE__, __LINE__, "sb",
50910 strerror(errno), c->file.name);
50912 + return NETWORK_STATUS_FATAL_ERROR;
50916 offset = c->file.start + c->offset;
50917 /* limit the toSend to 2^31-1 bytes in a chunk */
50918 - toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
50919 + toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
50920 ((1 << 30) - 1) : c->file.length - c->offset;
50923 if (offset > sce->st.st_size) {
50924 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
50928 + return NETWORK_STATUS_FATAL_ERROR;
50932 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
50933 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
50937 + return NETWORK_STATUS_FATAL_ERROR;
50944 /* FreeBSD sendfile() */
50945 - if (-1 == sendfile(ifd, fd, offset, toSend, NULL, &r, 0)) {
50946 + if (-1 == sendfile(ifd, sock->fd, offset, toSend, NULL, &r, 0)) {
50953 + return NETWORK_STATUS_CONNECTION_CLOSE;
50955 log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
50958 + return NETWORK_STATUS_FATAL_ERROR;
50965 cq->bytes_out += r;
50968 if (c->offset == c->file.length) {
50969 chunk_finished = 1;
50978 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
50982 + return NETWORK_STATUS_FATAL_ERROR;
50986 if (!chunk_finished) {
50987 /* not finished yet */
50991 + return NETWORK_STATUS_WAIT_FOR_EVENT;
50995 - return chunks_written;
50996 + return NETWORK_STATUS_SUCCESS;
51000 --- ../lighttpd-1.4.11/src/network_linux_sendfile.c 2006-02-15 20:02:36.000000000 +0200
51001 +++ lighttpd-1.5.0/src/network_linux_sendfile.c 2006-09-07 00:57:05.000000000 +0300
51002 @@ -26,122 +26,54 @@
51003 /* on linux 2.4.29 + debian/ubuntu we have crashes if this is enabled */
51004 #undef HAVE_POSIX_FADVISE
51006 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
51008 +NETWORK_BACKEND_WRITE(linuxsendfile) {
51010 size_t chunks_written = 0;
51013 for(c = cq->first; c; c = c->next, chunks_written++) {
51014 int chunk_finished = 0;
51016 + network_status_t ret;
51019 - case MEM_CHUNK: {
51024 - size_t num_chunks, i;
51025 - struct iovec chunks[UIO_MAXIOV];
51027 - size_t num_bytes = 0;
51029 - /* we can't send more then SSIZE_MAX bytes in one chunk */
51031 - /* build writev list
51033 - * 1. limit: num_chunks < UIO_MAXIOV
51034 - * 2. limit: num_bytes < SSIZE_MAX
51036 - for (num_chunks = 0, tc = c;
51037 - tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV;
51038 - tc = tc->next, num_chunks++);
51040 - for (tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
51041 - if (tc->mem->used == 0) {
51042 - chunks[i].iov_base = tc->mem->ptr;
51043 - chunks[i].iov_len = 0;
51045 - offset = tc->mem->ptr + tc->offset;
51046 - toSend = tc->mem->used - 1 - tc->offset;
51048 - chunks[i].iov_base = offset;
51050 - /* protect the return value of writev() */
51051 - if (toSend > SSIZE_MAX ||
51052 - num_bytes + toSend > SSIZE_MAX) {
51053 - chunks[i].iov_len = SSIZE_MAX - num_bytes;
51055 - num_chunks = i + 1;
51058 - chunks[i].iov_len = toSend;
51061 - num_bytes += toSend;
51065 - if ((r = writev(fd, chunks, num_chunks)) < 0) {
51075 - log_error_write(srv, __FILE__, __LINE__, "ssd",
51076 - "writev failed:", strerror(errno), fd);
51082 - /* check which chunks have been written */
51083 - cq->bytes_out += r;
51085 + ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
51087 - for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
51088 - if (r >= (ssize_t)chunks[i].iov_len) {
51090 - r -= chunks[i].iov_len;
51091 - tc->offset += chunks[i].iov_len;
51093 + /* check which chunks are finished now */
51094 + for (tc = c; tc; tc = tc->next) {
51095 + /* finished the chunk */
51096 + if (tc->offset == tc->mem->used - 1) {
51097 + /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
51098 if (chunk_finished) {
51099 - /* skip the chunks from further touches */
51100 - chunks_written++;
51103 - /* chunks_written + c = c->next is done in the for()*/
51104 - chunk_finished++;
51105 + chunk_finished = 1;
51108 - /* partially written */
51111 - chunk_finished = 0;
51118 + if (ret != NETWORK_STATUS_SUCCESS) {
51128 stat_cache_entry *sce = NULL;
51131 offset = c->file.start + c->offset;
51132 /* limit the toSend to 2^31-1 bytes in a chunk */
51133 - toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
51134 + toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
51135 ((1 << 30) - 1) : c->file.length - c->offset;
51137 - /* open file if not already opened */
51139 + /* open file if not already opened */
51140 if (-1 == c->file.fd) {
51141 if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
51142 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
51148 @@ -151,26 +83,25 @@
51149 /* tell the kernel that we want to stream the file */
51150 if (-1 == posix_fadvise(c->file.fd, 0, 0, POSIX_FADV_SEQUENTIAL)) {
51151 if (ENOSYS != errno) {
51152 - log_error_write(srv, __FILE__, __LINE__, "ssd",
51153 + log_error_write(srv, __FILE__, __LINE__, "ssd",
51154 "posix_fadvise failed:", strerror(errno), c->file.fd);
51160 - if (-1 == (r = sendfile(fd, c->file.fd, &offset, toSend))) {
51161 + if (-1 == (r = sendfile(sock->fd, c->file.fd, &offset, toSend))) {
51167 + return NETWORK_STATUS_WAIT_FOR_EVENT;
51171 + return NETWORK_STATUS_CONNECTION_CLOSE;
51173 - log_error_write(srv, __FILE__, __LINE__, "ssd",
51174 - "sendfile failed:", strerror(errno), fd);
51176 + log_error_write(srv, __FILE__, __LINE__, "ssd",
51177 + "sendfile failed:", strerror(errno), sock->fd);
51178 + return NETWORK_STATUS_FATAL_ERROR;
51182 @@ -179,39 +110,39 @@
51184 * - the file shrinked -> error
51185 * - the remote side closed inbetween -> remote-close */
51188 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
51189 /* file is gone ? */
51191 + return NETWORK_STATUS_FATAL_ERROR;
51194 if (offset > sce->st.st_size) {
51195 /* file shrinked, close the connection */
51197 + return NETWORK_STATUS_FATAL_ERROR;
51201 + return NETWORK_STATUS_CONNECTION_CLOSE;
51204 #ifdef HAVE_POSIX_FADVISE
51207 -#define M * 1024 K
51208 +#define M * 1024 K
51209 #define READ_AHEAD 4 M
51210 /* check if we need a new chunk */
51211 if ((c->offset & ~(READ_AHEAD - 1)) != ((c->offset + r) & ~(READ_AHEAD - 1))) {
51212 /* tell the kernel that we want to stream the file */
51213 if (-1 == posix_fadvise(c->file.fd, (c->offset + r) & ~(READ_AHEAD - 1), READ_AHEAD, POSIX_FADV_NOREUSE)) {
51214 - log_error_write(srv, __FILE__, __LINE__, "ssd",
51215 + log_error_write(srv, __FILE__, __LINE__, "ssd",
51216 "posix_fadvise failed:", strerror(errno), c->file.fd);
51224 cq->bytes_out += r;
51227 if (c->offset == c->file.length) {
51228 chunk_finished = 1;
51230 @@ -222,24 +153,24 @@
51241 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
51245 + return NETWORK_STATUS_FATAL_ERROR;
51249 if (!chunk_finished) {
51250 /* not finished yet */
51254 + return NETWORK_STATUS_WAIT_FOR_EVENT;
51258 - return chunks_written;
51259 + return NETWORK_STATUS_SUCCESS;
51263 --- ../lighttpd-1.4.11/src/network_openssl.c 2005-11-17 14:53:29.000000000 +0200
51264 +++ lighttpd-1.5.0/src/network_openssl.c 2006-09-07 00:57:05.000000000 +0300
51265 @@ -23,17 +23,94 @@
51267 #include "stat_cache.h"
51269 -# include <openssl/ssl.h>
51270 -# include <openssl/err.h>
51271 +# include <openssl/ssl.h>
51272 +# include <openssl/err.h>
51274 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq) {
51275 +NETWORK_BACKEND_READ(openssl) {
51278 + int read_something = 0;
51279 + off_t max_read = 256 * 1024;
51281 + off_t start_bytes_in = cq->bytes_in;
51283 + b = chunkqueue_get_append_buffer(cq);
51284 + buffer_prepare_copy(b, 8192 + 12); /* ssl-chunk-size is 8kb */
51285 + len = SSL_read(sock->ssl, b->ptr, b->size - 1);
51290 + switch ((r = SSL_get_error(sock->ssl, len))) {
51291 + case SSL_ERROR_WANT_READ:
51292 + chunkqueue_remove_empty_last_chunk(cq);
51293 + return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
51294 + case SSL_ERROR_SYSCALL:
51296 + * man SSL_get_error()
51298 + * SSL_ERROR_SYSCALL
51299 + * Some I/O error occurred. The OpenSSL error queue may contain more
51300 + * information on the error. If the error queue is empty (i.e.
51301 + * ERR_get_error() returns 0), ret can be used to find out more about
51302 + * the error: If ret == 0, an EOF was observed that violates the
51303 + * protocol. If ret == -1, the underlying BIO reported an I/O error
51304 + * (for socket I/O on Unix systems, consult errno for details).
51307 + while((ssl_err = ERR_get_error())) {
51308 + /* get all errors from the error-queue */
51309 + ERROR("ssl-errors: %s", ERR_error_string(ssl_err, NULL));
51314 + ERROR("last-errno: (%d) %s", errno, strerror(errno));
51319 + case SSL_ERROR_ZERO_RETURN:
51320 + /* clean shutdown on the remote side */
51323 + /* FIXME: later */
51326 + /* fall through */
51328 + while((ssl_err = ERR_get_error())) {
51329 + /* get all errors from the error-queue */
51330 + ERROR("ssl-errors: %s", ERR_error_string(ssl_err, NULL));
51333 + return NETWORK_STATUS_FATAL_ERROR;
51335 + } else if (len == 0) {
51336 + return NETWORK_STATUS_FATAL_ERROR;
51339 + b->ptr[b->used++] = '\0';
51341 + read_something = 1;
51342 + cq->bytes_in += len;
51345 + if (cq->bytes_in - start_bytes_in > max_read) return NETWORK_STATUS_SUCCESS;
51348 + return NETWORK_STATUS_FATAL_ERROR;
51352 +NETWORK_BACKEND_WRITE(openssl) {
51355 size_t chunks_written = 0;
51357 /* this is a 64k sendbuffer
51359 - * it has to stay at the same location all the time to satisfy the needs
51360 + * it has to stay at the same location all the time to satisfy the needs
51361 * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
51363 * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
51364 @@ -43,59 +120,61 @@
51365 * In reality we would like to use mmap() but we don't have a guarantee that
51366 * we get the same mmap() address for each call. On openbsd the mmap() address
51368 - * That means either we keep the mmap() open or we do a read() into a
51369 - * constant buffer
51370 + * That means either we keep the mmap() open or we do a read() into a
51371 + * constant buffer
51373 #define LOCAL_SEND_BUFSIZE (64 * 1024)
51374 static char *local_send_buffer = NULL;
51376 /* the remote side closed the connection before without shutdown request
51380 * if keep-alive is disabled */
51382 if (con->keep_alive == 0) {
51383 - SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
51384 + SSL_set_shutdown(sock->ssl, SSL_RECEIVED_SHUTDOWN);
51387 for(c = cq->first; c; c = c->next) {
51388 int chunk_finished = 0;
51399 if (c->mem->used == 0) {
51400 chunk_finished = 1;
51405 offset = c->mem->ptr + c->offset;
51406 toSend = c->mem->used - 1 - c->offset;
51410 * SSL_write man-page
51414 * When an SSL_write() operation has to be repeated because of
51415 * SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
51416 * repeated with the same arguments.
51419 + * SSL_write(..., 0) return 0 which is handle as an error (Success)
51420 + * checking toSend and not calling SSL_write() is simpler
51423 - if ((r = SSL_write(ssl, offset, toSend)) <= 0) {
51425 + if (toSend != 0 && (r = SSL_write(sock->ssl, offset, toSend)) <= 0) {
51428 - switch ((ssl_r = SSL_get_error(ssl, r))) {
51429 + switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
51430 case SSL_ERROR_WANT_WRITE:
51432 case SSL_ERROR_SYSCALL:
51433 /* perhaps we have error waiting in our error-queue */
51434 if (0 != (err = ERR_get_error())) {
51436 - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
51437 + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
51439 ERR_error_string(err, NULL));
51440 } while((err = ERR_get_error()));
51441 @@ -105,43 +184,43 @@
51445 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
51446 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
51452 /* neither error-queue nor errno ? */
51453 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
51454 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
51461 case SSL_ERROR_ZERO_RETURN:
51462 /* clean shutdown on the remote side */
51465 if (r == 0) return -2;
51470 while((err = ERR_get_error())) {
51471 - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
51472 + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
51474 ERR_error_string(err, NULL));
51482 cq->bytes_out += r;
51486 if (c->offset == (off_t)c->mem->used - 1) {
51487 chunk_finished = 1;
51494 @@ -150,7 +229,7 @@
51495 stat_cache_entry *sce = NULL;
51497 int write_wait = 0;
51500 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
51501 log_error_write(srv, __FILE__, __LINE__, "sb",
51502 strerror(errno), c->file.name);
51503 @@ -164,13 +243,13 @@
51506 off_t offset = c->file.start + c->offset;
51507 - off_t toSend = c->file.length - c->offset;
51508 + off_t toSend = c->file.length - c->offset;
51510 if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
51513 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
51514 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed:", strerror(errno));
51520 @@ -183,13 +262,13 @@
51523 s = local_send_buffer;
51528 - if ((r = SSL_write(ssl, s, toSend)) <= 0) {
51530 + if ((r = SSL_write(sock->ssl, s, toSend)) <= 0) {
51533 - switch ((ssl_r = SSL_get_error(ssl, r))) {
51534 + switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
51535 case SSL_ERROR_WANT_WRITE:
51538 @@ -197,7 +276,7 @@
51539 /* perhaps we have error waiting in our error-queue */
51540 if (0 != (err = ERR_get_error())) {
51542 - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
51543 + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
51545 ERR_error_string(err, NULL));
51546 } while((err = ERR_get_error()));
51547 @@ -207,62 +286,62 @@
51551 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
51552 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
51558 /* neither error-queue nor errno ? */
51559 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
51560 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
51567 case SSL_ERROR_ZERO_RETURN:
51568 /* clean shutdown on the remote side */
51571 if (r == 0) return -2;
51576 while((err = ERR_get_error())) {
51577 - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
51578 + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
51580 ERR_error_string(err, NULL));
51588 cq->bytes_out += r;
51592 if (c->offset == c->file.length) {
51593 chunk_finished = 1;
51595 } while(!chunk_finished && !write_wait);
51601 log_error_write(srv, __FILE__, __LINE__, "s", "type not known");
51608 if (!chunk_finished) {
51609 /* not finished yet */
51619 - return chunks_written;
51620 + return NETWORK_STATUS_SUCCESS;
51624 --- ../lighttpd-1.4.11/src/network_solaris_sendfilev.c 2005-10-22 12:28:27.000000000 +0300
51625 +++ lighttpd-1.5.0/src/network_solaris_sendfilev.c 2006-07-16 00:26:04.000000000 +0300
51626 @@ -29,114 +29,34 @@
51630 - * a very simple sendfilev() interface for solaris which can be optimised a lot more
51631 + * a very simple sendfilev() interface for solaris which can be optimised a lot more
51632 * as solaris sendfilev() supports 'sending everythin in one syscall()'
51634 - * If you want such an interface and need the performance, just give me an account on
51637 + * If you want such an interface and need the performance, just give me an account on
51639 * - jan@kneschke.de
51643 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq) {
51644 +NETWORK_BACKEND_WRITE(solarissendfilev) {
51646 size_t chunks_written = 0;
51649 for(c = cq->first; c; c = c->next, chunks_written++) {
51650 int chunk_finished = 0;
51652 + network_status_t ret;
51655 - case MEM_CHUNK: {
51660 - size_t num_chunks, i;
51661 - struct iovec chunks[UIO_MAXIOV];
51664 - size_t num_bytes = 0;
51666 - /* we can't send more then SSIZE_MAX bytes in one chunk */
51668 - /* build writev list
51670 - * 1. limit: num_chunks < UIO_MAXIOV
51671 - * 2. limit: num_bytes < SSIZE_MAX
51673 - for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
51675 - for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
51676 - if (tc->mem->used == 0) {
51677 - chunks[i].iov_base = tc->mem->ptr;
51678 - chunks[i].iov_len = 0;
51680 - offset = tc->mem->ptr + tc->offset;
51681 - toSend = tc->mem->used - 1 - tc->offset;
51683 - chunks[i].iov_base = offset;
51685 - /* protect the return value of writev() */
51686 - if (toSend > SSIZE_MAX ||
51687 - num_bytes + toSend > SSIZE_MAX) {
51688 - chunks[i].iov_len = SSIZE_MAX - num_bytes;
51690 - num_chunks = i + 1;
51693 - chunks[i].iov_len = toSend;
51696 - num_bytes += toSend;
51700 - if ((r = writev(fd, chunks, num_chunks)) < 0) {
51710 - log_error_write(srv, __FILE__, __LINE__, "ssd",
51711 - "writev failed:", strerror(errno), fd);
51717 - /* check which chunks have been written */
51718 - cq->bytes_out += r;
51720 - for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
51721 - if (r >= (ssize_t)chunks[i].iov_len) {
51723 - r -= chunks[i].iov_len;
51724 - tc->offset += chunks[i].iov_len;
51726 - if (chunk_finished) {
51727 - /* skip the chunks from further touches */
51728 - chunks_written++;
51731 - /* chunks_written + c = c->next is done in the for()*/
51732 - chunk_finished++;
51735 - /* partially written */
51738 - chunk_finished = 0;
51743 + ret = network_write_chunkqueue_writev_mem(srv, con, fd, cq, &c);
51745 + if (ret != NETWORK_STATUS_SUCCESS) {
51750 + chunk_finished = 1;
51757 @@ -144,25 +64,25 @@
51758 sendfilevec_t fvec;
51759 stat_cache_entry *sce = NULL;
51763 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
51764 log_error_write(srv, __FILE__, __LINE__, "sb",
51765 strerror(errno), c->file.name);
51770 offset = c->file.start + c->offset;
51771 toSend = c->file.length - c->offset;
51774 if (offset > sce->st.st_size) {
51775 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
51781 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
51782 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
51788 @@ -170,44 +90,43 @@
51790 fvec.sfv_off = offset;
51791 fvec.sfv_len = toSend;
51794 /* Solaris sendfilev() */
51795 if (-1 == (r = sendfilev(fd, &fvec, 1, &written))) {
51796 if (errno != EAGAIN) {
51797 log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
51802 + return NETWORK_STATUS_FATAL_ERROR;
51811 c->offset += written;
51812 cq->bytes_out += written;
51815 if (c->offset == c->file.length) {
51816 chunk_finished = 1;
51824 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
51828 + return NETWORK_STATUS_FATAL_ERROR;
51832 if (!chunk_finished) {
51833 /* not finished yet */
51840 - return chunks_written;
51841 + return NETWORK_STATUS_SUCCESS;
51845 --- ../lighttpd-1.4.11/src/network_write.c 2005-10-22 12:27:56.000000000 +0300
51846 +++ lighttpd-1.5.0/src/network_write.c 2006-09-07 00:57:05.000000000 +0300
51848 #include <sys/types.h>
51849 #include <sys/stat.h>
51850 -#include <sys/time.h>
51854 -#include <unistd.h>
51855 #include <string.h>
51856 #include <stdlib.h>
51857 +#include <assert.h>
51859 #include "network.h"
51860 #include "fdevent.h"
51862 #include "stat_cache.h"
51864 #include "sys-socket.h"
51865 +#include "sys-files.h"
51867 #include "network_backends.h"
51871 #ifdef HAVE_SYS_FILIO_H
51872 # include <sys/filio.h>
51874 @@ -24,47 +27,100 @@
51875 #include <sys/resource.h>
51878 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq) {
51881 +* fill the chunkqueue will all the data that we can get
51883 +* this might be optimized into a readv() which uses the chunks
51886 +NETWORK_BACKEND_READ(read) {
51889 + off_t r, start_bytes_in;
51890 + off_t max_read = 256 * 1024;
51893 + * a EAGAIN is a successful read if we already read something to the chunkqueue
51895 + int read_something = 0;
51897 + start_bytes_in = cq->bytes_in;
51899 + /* use a chunk-size of 16k */
51903 + b = chunkqueue_get_append_buffer(cq);
51905 + buffer_prepare_copy(b, toread);
51907 + if (-1 == (r = read(sock->fd, b->ptr, toread))) {
51910 + /* remove the last chunk from the chunkqueue */
51911 + chunkqueue_remove_empty_last_chunk(cq);
51912 + return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
51914 + return NETWORK_STATUS_CONNECTION_CLOSE;
51916 + ERROR("oops, read from fd=%d failed: %s (%d)", sock->fd, strerror(errno), errno );
51918 + return NETWORK_STATUS_FATAL_ERROR;
51923 + chunkqueue_remove_empty_last_chunk(cq);
51924 + return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_CONNECTION_CLOSE;
51927 + read_something = 1;
51930 + b->ptr[b->used++] = '\0';
51931 + cq->bytes_in += r;
51933 + if (cq->bytes_in - start_bytes_in > max_read) break;
51934 + } while (r == toread);
51936 + return NETWORK_STATUS_SUCCESS;
51939 +NETWORK_BACKEND_WRITE(write) {
51941 size_t chunks_written = 0;
51944 for(c = cq->first; c; c = c->next) {
51945 int chunk_finished = 0;
51955 if (c->mem->used == 0) {
51956 chunk_finished = 1;
51961 offset = c->mem->ptr + c->offset;
51962 toSend = c->mem->used - 1 - c->offset;
51964 - if ((r = send(fd, offset, toSend, 0)) < 0) {
51965 - log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
51970 - if ((r = write(fd, offset, toSend)) < 0) {
51971 - log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
51975 + if ((r = write(sock->fd, offset, toSend)) < 0) {
51976 + log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), sock->fd);
51978 + return NETWORK_STATUS_FATAL_ERROR;
51984 cq->bytes_out += r;
51987 if (c->offset == (off_t)c->mem->used - 1) {
51988 chunk_finished = 1;
51995 @@ -76,93 +132,89 @@
51997 stat_cache_entry *sce = NULL;
52001 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
52002 log_error_write(srv, __FILE__, __LINE__, "sb",
52003 strerror(errno), c->file.name);
52005 + return NETWORK_STATUS_FATAL_ERROR;
52009 offset = c->file.start + c->offset;
52010 toSend = c->file.length - c->offset;
52013 if (offset > sce->st.st_size) {
52014 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
52018 + return NETWORK_STATUS_FATAL_ERROR;
52021 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
52022 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
52026 + return NETWORK_STATUS_FATAL_ERROR;
52030 #if defined USE_MMAP
52031 if (MAP_FAILED == (p = mmap(0, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
52032 log_error_write(srv, __FILE__, __LINE__, "ss", "mmap failed: ", strerror(errno));
52038 + return NETWORK_STATUS_FATAL_ERROR;
52042 - if ((r = write(fd, p + offset, toSend)) <= 0) {
52043 + if ((r = write(sock->fd, p + offset, toSend)) <= 0) {
52044 log_error_write(srv, __FILE__, __LINE__, "ss", "write failed: ", strerror(errno));
52045 munmap(p, sce->st.st_size);
52047 + return NETWORK_STATUS_FATAL_ERROR;
52051 munmap(p, sce->st.st_size);
52053 buffer_prepare_copy(srv->tmp_buf, toSend);
52056 lseek(ifd, offset, SEEK_SET);
52057 if (-1 == (toSend = read(ifd, srv->tmp_buf->ptr, toSend))) {
52058 log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
52063 + return NETWORK_STATUS_FATAL_ERROR;
52067 - if (-1 == (r = send(fd, srv->tmp_buf->ptr, toSend, 0))) {
52068 + if (-1 == (r = send(sock->fd, srv->tmp_buf->ptr, toSend, 0))) {
52069 log_error_write(srv, __FILE__, __LINE__, "ss", "write: ", strerror(errno));
52073 + return NETWORK_STATUS_FATAL_ERROR;
52077 cq->bytes_out += r;
52080 if (c->offset == c->file.length) {
52081 chunk_finished = 1;
52090 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
52094 + return NETWORK_STATUS_FATAL_ERROR;
52098 if (!chunk_finished) {
52099 /* not finished yet */
52109 - return chunks_written;
52110 + return NETWORK_STATUS_SUCCESS;
52114 -network_write_init(void) {
52115 - p->write = network_write_write_chunkset;
52118 --- ../lighttpd-1.4.11/src/network_writev.c 2006-02-15 01:02:36.000000000 +0200
52119 +++ lighttpd-1.5.0/src/network_writev.c 2006-07-18 13:03:40.000000000 +0300
52120 @@ -28,10 +28,10 @@
52123 # if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__)
52124 -/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */
52125 +/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */
52126 # define UIO_MAXIOV 1024
52127 # elif defined(__sgi)
52128 -/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */
52129 +/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */
52130 # define UIO_MAXIOV 512
52131 # elif defined(__sun)
52132 /* Solaris (and SunOS?) defines IOV_MAX instead */
52133 @@ -51,105 +51,121 @@
52134 #define LOCAL_BUFFERING 1
52137 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq) {
52139 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem) {
52144 + size_t num_chunks, i;
52145 + struct iovec chunks[UIO_MAXIOV];
52146 + chunk *tc; /* transfer chunks */
52147 + size_t num_bytes = 0;
52149 + /* we can't send more then SSIZE_MAX bytes in one chunk */
52151 + /* build writev list
52153 + * 1. limit: num_chunks < UIO_MAXIOV
52154 + * 2. limit: num_bytes < SSIZE_MAX
52156 + for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
52158 + for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
52159 + if (tc->mem->used == 0) {
52160 + chunks[i].iov_base = tc->mem->ptr;
52161 + chunks[i].iov_len = 0;
52163 + offset = tc->mem->ptr + tc->offset;
52164 + toSend = tc->mem->used - 1 - tc->offset;
52166 + chunks[i].iov_base = offset;
52168 + /* protect the return value of writev() */
52169 + if (toSend > SSIZE_MAX ||
52170 + num_bytes + toSend > SSIZE_MAX) {
52171 + chunks[i].iov_len = SSIZE_MAX - num_bytes;
52173 + num_chunks = i + 1;
52176 + chunks[i].iov_len = toSend;
52179 + num_bytes += toSend;
52183 + if ((r = writev(sock->fd, chunks, num_chunks)) < 0) {
52186 + return NETWORK_STATUS_WAIT_FOR_EVENT;
52188 + return NETWORK_STATUS_INTERRUPTED;
52191 + return NETWORK_STATUS_CONNECTION_CLOSE;
52193 + log_error_write(srv, __FILE__, __LINE__, "ssd",
52194 + "writev failed:", strerror(errno), sock->fd);
52196 + return NETWORK_STATUS_FATAL_ERROR;
52200 + cq->bytes_out += r;
52202 + /* check which chunks have been written */
52204 + for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
52205 + if (r >= (ssize_t)chunks[i].iov_len) {
52207 + r -= chunks[i].iov_len;
52208 + tc->offset += chunks[i].iov_len;
52210 + /* partially written */
52214 + return NETWORK_STATUS_WAIT_FOR_EVENT;
52218 + /* all chunks have been pushed out */
52219 + return NETWORK_STATUS_SUCCESS;
52222 +NETWORK_BACKEND_WRITE(writev) {
52224 size_t chunks_written = 0;
52227 for(c = cq->first; c; c = c->next) {
52228 int chunk_finished = 0;
52230 + network_status_t ret;
52233 - case MEM_CHUNK: {
52238 - size_t num_chunks, i;
52239 - struct iovec chunks[UIO_MAXIOV];
52241 - size_t num_bytes = 0;
52243 - /* we can't send more then SSIZE_MAX bytes in one chunk */
52245 - /* build writev list
52247 - * 1. limit: num_chunks < UIO_MAXIOV
52248 - * 2. limit: num_bytes < SSIZE_MAX
52250 - for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
52252 - for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
52253 - if (tc->mem->used == 0) {
52254 - chunks[i].iov_base = tc->mem->ptr;
52255 - chunks[i].iov_len = 0;
52257 - offset = tc->mem->ptr + tc->offset;
52258 - toSend = tc->mem->used - 1 - tc->offset;
52260 - chunks[i].iov_base = offset;
52262 - /* protect the return value of writev() */
52263 - if (toSend > SSIZE_MAX ||
52264 - num_bytes + toSend > SSIZE_MAX) {
52265 - chunks[i].iov_len = SSIZE_MAX - num_bytes;
52267 - num_chunks = i + 1;
52270 - chunks[i].iov_len = toSend;
52273 - num_bytes += toSend;
52277 - if ((r = writev(fd, chunks, num_chunks)) < 0) {
52287 - log_error_write(srv, __FILE__, __LINE__, "ssd",
52288 - "writev failed:", strerror(errno), fd);
52294 - cq->bytes_out += r;
52296 + ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
52298 - /* check which chunks have been written */
52300 - for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
52301 - if (r >= (ssize_t)chunks[i].iov_len) {
52303 - r -= chunks[i].iov_len;
52304 - tc->offset += chunks[i].iov_len;
52306 + /* check which chunks are finished now */
52307 + for (tc = c; tc; tc = tc->next) {
52308 + /* finished the chunk */
52309 + if (tc->offset == tc->mem->used - 1) {
52310 + /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
52311 if (chunk_finished) {
52312 - /* skip the chunks from further touches */
52313 - chunks_written++;
52316 - /* chunks_written + c = c->next is done in the for()*/
52317 - chunk_finished++;
52318 + chunk_finished = 1;
52321 - /* partially written */
52324 - chunk_finished = 0;
52331 + if (ret != NETWORK_STATUS_SUCCESS) {
52340 @@ -159,26 +175,26 @@
52341 #define KByte * 1024
52342 #define MByte * 1024 KByte
52343 #define GByte * 1024 MByte
52344 - const off_t we_want_to_mmap = 512 KByte;
52345 + const off_t we_want_to_mmap = 512 KByte;
52346 char *start = NULL;
52348 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
52349 log_error_write(srv, __FILE__, __LINE__, "sb",
52350 strerror(errno), c->file.name);
52352 + return NETWORK_STATUS_FATAL_ERROR;
52355 abs_offset = c->file.start + c->offset;
52358 if (abs_offset > sce->st.st_size) {
52359 - log_error_write(srv, __FILE__, __LINE__, "sb",
52360 + log_error_write(srv, __FILE__, __LINE__, "sb",
52361 "file was shrinked:", c->file.name);
52365 + return NETWORK_STATUS_FATAL_ERROR;
52368 - /* mmap the buffer
52370 + /* mmap the buffer
52372 * - new mmap as the we are at the end of the last one */
52373 if (c->file.mmap.start == MAP_FAILED ||
52374 abs_offset == (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
52375 @@ -188,7 +204,7 @@
52376 * adaptive mem-mapping
52378 * we mmap() the whole file. If someone has alot large files and 32bit
52379 - * machine the virtual address area will be unrun and we will have a failing
52380 + * machine the virtual address area will be unrun and we will have a failing
52383 * only mmap 16M in one chunk and move the window as soon as we have finished
52384 @@ -234,8 +250,8 @@
52385 if (-1 == c->file.fd) { /* open the file if not already open */
52386 if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
52387 log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno));
52391 + return NETWORK_STATUS_FATAL_ERROR;
52394 fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
52395 @@ -245,10 +261,10 @@
52396 if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
52397 /* close it here, otherwise we'd have to set FD_CLOEXEC */
52399 - log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
52400 + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
52401 strerror(errno), c->file.name, c->file.fd);
52404 + return NETWORK_STATUS_FATAL_ERROR;
52407 c->file.mmap.length = to_mmap;
52408 @@ -258,7 +274,7 @@
52409 #ifdef HAVE_MADVISE
52410 /* don't advise files < 64Kb */
52411 if (c->file.mmap.length > (64 KByte)) {
52412 - /* darwin 7 is returning EINVAL all the time and I don't know how to
52413 + /* darwin 7 is returning EINVAL all the time and I don't know how to
52414 * detect this at runtime.i
52416 * ignore the return value for now */
52417 @@ -274,12 +290,12 @@
52418 toSend = (c->file.mmap.offset + c->file.mmap.length) - (abs_offset);
52421 - log_error_write(srv, __FILE__, __LINE__, "soooo",
52422 + log_error_write(srv, __FILE__, __LINE__, "soooo",
52423 "toSend is negative:",
52425 c->file.mmap.length,
52427 - c->file.mmap.offset);
52428 + c->file.mmap.offset);
52429 assert(toSend < 0);
52432 @@ -289,7 +305,7 @@
52433 start = c->file.mmap.start;
52436 - if ((r = write(fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
52437 + if ((r = write(sock->fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
52441 @@ -297,18 +313,18 @@
52446 + return NETWORK_STATUS_CONNECTION_CLOSE;
52448 - log_error_write(srv, __FILE__, __LINE__, "ssd",
52449 - "write failed:", strerror(errno), fd);
52452 + log_error_write(srv, __FILE__, __LINE__, "ssd",
52453 + "write failed:", strerror(errno), sock->fd);
52455 + return NETWORK_STATUS_FATAL_ERROR;
52461 cq->bytes_out += r;
52464 if (c->offset == c->file.length) {
52465 chunk_finished = 1;
52467 @@ -318,26 +334,26 @@
52468 c->file.mmap.start = MAP_FAILED;
52478 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
52482 + return NETWORK_STATUS_FATAL_ERROR;
52486 if (!chunk_finished) {
52487 /* not finished yet */
52497 - return chunks_written;
52498 + return NETWORK_STATUS_SUCCESS;
52502 --- ../lighttpd-1.4.11/src/plugin.c 2006-02-08 14:00:54.000000000 +0200
52503 +++ lighttpd-1.5.0/src/plugin.c 2006-09-07 00:57:05.000000000 +0300
52504 @@ -13,69 +13,73 @@
52505 #include <valgrind/valgrind.h>
52515 * if you change this enum to add a new callback, be sure
52516 * - that PLUGIN_FUNC_SIZEOF is the last entry
52517 * - that you add PLUGIN_TO_SLOT twice:
52518 - * 1. as callback-dispatcher
52519 + * 1. as callback-dispatcher
52520 * 2. in plugins_call_init()
52532 - PLUGIN_FUNC_HANDLE_URI_CLEAN,
52533 - PLUGIN_FUNC_HANDLE_URI_RAW,
52534 - PLUGIN_FUNC_HANDLE_REQUEST_DONE,
52535 + PLUGIN_FUNC_HANDLE_URI_CLEAN,
52536 + PLUGIN_FUNC_HANDLE_URI_RAW,
52537 + PLUGIN_FUNC_HANDLE_RESPONSE_DONE,
52538 PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
52539 PLUGIN_FUNC_HANDLE_TRIGGER,
52540 PLUGIN_FUNC_HANDLE_SIGHUP,
52541 - PLUGIN_FUNC_HANDLE_SUBREQUEST,
52542 - PLUGIN_FUNC_HANDLE_SUBREQUEST_START,
52543 + PLUGIN_FUNC_HANDLE_START_BACKEND,
52544 + PLUGIN_FUNC_HANDLE_SEND_REQUEST_CONTENT,
52545 PLUGIN_FUNC_HANDLE_JOBLIST,
52546 PLUGIN_FUNC_HANDLE_DOCROOT,
52547 PLUGIN_FUNC_HANDLE_PHYSICAL,
52548 PLUGIN_FUNC_CONNECTION_RESET,
52549 - PLUGIN_FUNC_INIT,
52550 + PLUGIN_FUNC_INIT,
52551 PLUGIN_FUNC_CLEANUP,
52552 PLUGIN_FUNC_SET_DEFAULTS,
52558 static plugin *plugin_init(void) {
52562 p = calloc(1, sizeof(*p));
52565 + p->required_plugins = array_init();
52570 static void plugin_free(plugin *p) {
52571 int use_dlclose = 1;
52572 if (p->name) buffer_free(p->name);
52574 + array_free(p->required_plugins);
52575 #ifdef HAVE_VALGRIND_VALGRIND_H
52576 /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
52579 #ifndef LIGHTTPD_STATIC
52580 - if (use_dlclose && p->lib) {
52582 + if (use_dlclose && p->lib) {
52584 FreeLibrary(p->lib);
52595 @@ -89,17 +93,17 @@
52596 srv->plugins.size += 4;
52597 srv->plugins.ptr = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
52601 ps = srv->plugins.ptr;
52602 ps[srv->plugins.used++] = p;
52617 #ifdef LIGHTTPD_STATIC
52618 @@ -121,30 +125,35 @@
52620 int plugins_load(server *srv) {
52625 int (*init)(plugin *pl);
52633 for (i = 0; i < srv->srvconf.modules->used; i++) {
52634 data_string *d = (data_string *)srv->srvconf.modules->data[i];
52635 char *modules = d->value->ptr;
52638 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
52640 buffer_append_string(srv->tmp_buf, "/");
52641 buffer_append_string(srv->tmp_buf, modules);
52642 -#if defined(__WIN32) || defined(__CYGWIN__)
52643 +#if defined(_WIN32) || defined(__CYGWIN__)
52644 buffer_append_string(srv->tmp_buf, ".dll");
52646 buffer_append_string(srv->tmp_buf, ".so");
52653 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
52656 - FORMAT_MESSAGE_ALLOCATE_BUFFER |
52657 + FORMAT_MESSAGE_ALLOCATE_BUFFER |
52658 FORMAT_MESSAGE_FROM_SYSTEM,
52661 @@ -152,36 +161,36 @@
52662 (LPTSTR) &lpMsgBuf,
52665 - log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
52666 + log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
52667 lpMsgBuf, srv->tmp_buf);
52678 if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_LAZY))) {
52679 - log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
52680 + log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
52681 srv->tmp_buf, dlerror());
52692 buffer_reset(srv->tmp_buf);
52693 buffer_copy_string(srv->tmp_buf, modules);
52694 buffer_append_string(srv->tmp_buf, "_plugin_init");
52698 init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
52700 if (init == NULL) {
52703 - FORMAT_MESSAGE_ALLOCATE_BUFFER |
52704 + FORMAT_MESSAGE_ALLOCATE_BUFFER |
52705 FORMAT_MESSAGE_FROM_SYSTEM,
52708 @@ -190,7 +199,7 @@
52711 log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
52717 @@ -203,24 +212,43 @@
52719 if ((error = dlerror()) != NULL) {
52720 log_error_write(srv, __FILE__, __LINE__, "s", error);
52730 log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin init failed" );
52737 log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin loaded" );
52739 + /* check if the required plugin is loaded */
52740 + for (k = 0; k < p->required_plugins->used; k++) {
52741 + data_string *req = (data_string *)p->required_plugins->data[k];
52743 + for (j = 0; j < i; j++) {
52744 + data_string *mod = (data_string *)srv->srvconf.modules->data[j];
52746 + if (buffer_is_equal(req->value, mod->value)) break;
52751 + log_error_write(srv, __FILE__, __LINE__, "ssbs", modules, "failed to load. required plugin", req->value, "was not loaded" );
52758 plugins_register(srv, p);
52765 @@ -253,8 +281,8 @@
52769 - * plugins that use
52771 + * plugins that use
52774 * - connection *con
52775 * - void *p_d (plugin_data *)
52776 @@ -262,13 +290,13 @@
52778 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean)
52779 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw)
52780 -PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done)
52781 -PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close)
52782 -PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest)
52783 -PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start)
52784 -PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist)
52785 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot)
52786 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical)
52787 +PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_START_BACKEND, handle_start_backend)
52788 +PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SEND_REQUEST_CONTENT, handle_send_request_content)
52789 +PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close)
52790 +PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_DONE, handle_response_done)
52791 +PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist)
52792 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset)
52794 #undef PLUGIN_TO_SLOT
52795 @@ -301,12 +329,12 @@
52799 - * plugins that use
52801 + * plugins that use
52804 * - void *p_d (plugin_data *)
52808 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
52809 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
52810 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
52811 @@ -314,18 +342,18 @@
52813 #undef PLUGIN_TO_SLOT
52824 handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
52829 ps = srv->plugins.ptr;
52832 for (i = 0; i < srv->plugins.used; i++) {
52834 if (p->handle_fdevent) {
52835 @@ -344,34 +372,34 @@
52841 return HANDLER_GO_ON;
52847 * - call init function of all plugins to init the plugin-internals
52848 * - added each plugin that supports has callback to the corresponding slot
52851 * - is only called once.
52854 handler_t plugins_call_init(server *srv) {
52859 ps = srv->plugins.ptr;
52865 srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
52868 for (i = 0; i < srv->plugins.used; i++) {
52870 /* check which calls are supported */
52876 #define PLUGIN_TO_SLOT(x, y) \
52878 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
52879 @@ -384,37 +412,38 @@
52886 - PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
52887 - PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
52888 - PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
52889 - PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
52890 - PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
52891 - PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup);
52892 - PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest);
52893 - PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start);
52894 - PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist);
52898 + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
52899 + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
52900 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot);
52901 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical);
52902 + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_START_BACKEND, handle_start_backend);
52903 + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SEND_REQUEST_CONTENT, handle_send_request_content);
52904 + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_DONE, handle_response_done);
52905 + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
52907 + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist);
52908 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset);
52909 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
52910 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
52911 + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
52912 + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup);
52913 #undef PLUGIN_TO_SLOT
52917 if (NULL == (p->data = p->init())) {
52918 - log_error_write(srv, __FILE__, __LINE__, "sb",
52919 + log_error_write(srv, __FILE__, __LINE__, "sb",
52920 "plugin-init failed for module", p->name);
52921 return HANDLER_ERROR;
52925 /* used for con->mode, DIRECT == 0, plugins above that */
52926 ((plugin_data *)(p->data))->id = i + 1;
52929 if (p->version != LIGHTTPD_VERSION_ID) {
52930 - log_error_write(srv, __FILE__, __LINE__, "sb",
52931 + log_error_write(srv, __FILE__, __LINE__, "sb",
52932 "plugin-version doesn't match lighttpd-version for", p->name);
52933 return HANDLER_ERROR;
52935 @@ -422,29 +451,46 @@
52941 return HANDLER_GO_ON;
52945 + * get the config-storage of the named plugin
52947 +void *plugin_get_config(server *srv, const char *name) {
52950 + for (i = 0; i < srv->plugins.used; i++) {
52951 + plugin *p = ((plugin **)srv->plugins.ptr)[i];
52953 + if (buffer_is_equal_string(p->name, name, strlen(name))) {
52961 void plugins_free(server *srv) {
52963 plugins_call_cleanup(srv);
52966 for (i = 0; i < srv->plugins.used; i++) {
52967 plugin *p = ((plugin **)srv->plugins.ptr)[i];
52974 for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
52975 plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
52978 if (slot) free(slot);
52982 free(srv->plugin_slots);
52983 srv->plugin_slots = NULL;
52986 free(srv->plugins.ptr);
52987 srv->plugins.ptr = NULL;
52988 srv->plugins.used = 0;
52989 --- ../lighttpd-1.4.11/src/plugin.h 2005-08-15 12:28:56.000000000 +0300
52990 +++ lighttpd-1.5.0/src/plugin.h 2006-09-07 00:57:05.000000000 +0300
52993 #define INIT_FUNC(x) \
52996 + * The PATCH_OPTION() macro is used in the patch_connection() functions
52997 + * of the modules to update the config object for the current request.
52999 +#define PATCH_OPTION(x) \
53002 #define FREE_FUNC SERVER_FUNC
53003 #define TRIGGER_FUNC SERVER_FUNC
53004 @@ -25,40 +31,45 @@
53005 #define URIHANDLER_FUNC CONNECTION_FUNC
53007 #define PLUGIN_DATA size_t id
53011 + * we have 4 states on the connection:
53015 + * - write-content
53022 buffer *name; /* name of the plugin */
53026 handler_t (* set_defaults) (server *srv, void *p_d);
53027 handler_t (* cleanup) (server *srv, void *p_d);
53028 /* is called ... */
53029 handler_t (* handle_trigger) (server *srv, void *p_d); /* once a second */
53030 handler_t (* handle_sighup) (server *srv, void *p_d); /* at a signup */
53032 - handler_t (* handle_uri_raw) (server *srv, connection *con, void *p_d); /* after uri_raw is set */
53033 - handler_t (* handle_uri_clean) (server *srv, connection *con, void *p_d); /* after uri is set */
53034 - handler_t (* handle_docroot) (server *srv, connection *con, void *p_d); /* getting the document-root */
53035 - handler_t (* handle_physical) (server *srv, connection *con, void *p_d); /* mapping url to physical path */
53036 - handler_t (* handle_request_done) (server *srv, connection *con, void *p_d); /* at the end of a request */
53037 - handler_t (* handle_connection_close)(server *srv, connection *con, void *p_d); /* at the end of a connection */
53038 - handler_t (* handle_joblist) (server *srv, connection *con, void *p_d); /* after all events are handled */
53042 - handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);
53044 - /* when a handler for the request
53045 - * has to be found
53047 - handler_t (* handle_subrequest) (server *srv, connection *con, void *p_d); /* */
53048 - handler_t (* connection_reset) (server *srv, connection *con, void *p_d); /* */
53050 + handler_t (* handle_uri_raw) (server *srv, connection *con, void *p_d); /* after uri_raw is set (mod_rewrite) */
53051 + handler_t (* handle_uri_clean) (server *srv, connection *con, void *p_d); /* after uri is set (mod_access, mod_auth) */
53052 + handler_t (* handle_docroot) (server *srv, connection *con, void *p_d); /* getting the document-root (e.g. mod_simple_vhost) */
53053 + handler_t (* handle_physical) (server *srv, connection *con, void *p_d); /* mapping url to physical path (e.g. mod_alias, mod_proxy_core) */
53054 + handler_t (* handle_start_backend) (server *srv, connection *con, void *p_d); /* file exists locally (e.g. mod_staticfile) */
53055 + handler_t (* handle_send_request_content)(server *srv, connection *con, void *p_d); /* a handler for the request content */
53056 + handler_t (* handle_response_header) (server *srv, connection *con, void *p_d); /* a handler for the request content */
53057 + handler_t (* handle_response_done) (server *srv, connection *con, void *p_d); /* after the response is sent (e.g. mod_accesslog) */
53058 + handler_t (* connection_reset) (server *srv, connection *con, void *p_d); /* end of a request-response cycle (mod_acceslog, mod_proxy_core) */
53059 + handler_t (* handle_connection_close)(server *srv, connection *con, void *p_d); /* at the end of a connection [remove-me ?] */
53060 + handler_t (* handle_joblist) (server *srv, connection *con, void *p_d); /* after all events are handled [remove-me ?] */
53065 /* dlopen handle */
53068 + array *required_plugins;
53071 int plugins_load(server *srv);
53072 @@ -66,11 +77,12 @@
53074 handler_t plugins_call_handle_uri_raw(server *srv, connection *con);
53075 handler_t plugins_call_handle_uri_clean(server *srv, connection *con);
53076 -handler_t plugins_call_handle_subrequest_start(server *srv, connection *con);
53077 -handler_t plugins_call_handle_subrequest(server *srv, connection *con);
53078 -handler_t plugins_call_handle_request_done(server *srv, connection *con);
53079 handler_t plugins_call_handle_docroot(server *srv, connection *con);
53080 handler_t plugins_call_handle_physical(server *srv, connection *con);
53081 +handler_t plugins_call_handle_start_backend(server *srv, connection *con);
53082 +handler_t plugins_call_handle_send_request_content(server *srv, connection *con);
53083 +handler_t plugins_call_handle_response_header(server *srv, connection *con);
53084 +handler_t plugins_call_handle_response_done(server *srv, connection *con);
53085 handler_t plugins_call_handle_connection_close(server *srv, connection *con);
53086 handler_t plugins_call_handle_joblist(server *srv, connection *con);
53087 handler_t plugins_call_connection_reset(server *srv, connection *con);
53089 int config_patch_connection(server *srv, connection *con, comp_key_t comp);
53090 int config_check_cond(server *srv, connection *con, data_config *dc);
53091 int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n);
53092 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result);
53094 +void *plugin_get_config(server *srv, const char *name);
53097 --- ../lighttpd-1.4.11/src/proc_open.c 2005-08-11 01:26:39.000000000 +0300
53098 +++ lighttpd-1.5.0/src/proc_open.c 2006-07-16 00:26:04.000000000 +0300
53099 @@ -13,13 +13,13 @@
53105 /* {{{ win32 stuff */
53106 # define SHELLENV "ComSpec"
53107 # define SECURITY_DC , SECURITY_ATTRIBUTES *security
53108 # define SECURITY_CC , security
53109 # define pipe(pair) (CreatePipe(&pair[0], &pair[1], security, 2048L) ? 0 : -1)
53110 -static inline HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
53111 +static HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
53113 HANDLE copy, self = GetCurrentProcess();
53115 @@ -148,11 +148,14 @@
53118 SECURITY_ATTRIBUTES security;
53119 - const char *shell;
53120 + const char *shell = NULL;
53121 + const char *windir = NULL;
53124 - if (NULL == (shell = getenv(SHELLENV))) {
53125 - fprintf(stderr, "env %s is required", SHELLENV);
53126 + if (NULL == (shell = getenv(SHELLENV)) &&
53127 + NULL == (windir = getenv("SystemRoot")) &&
53128 + NULL == (windir = getenv("windir"))) {
53129 + fprintf(stderr, "One of %s,%%SystemRoot,%%windir is required", SHELLENV);
53133 @@ -177,17 +180,23 @@
53134 memset(&pi, 0, sizeof(pi));
53136 cmdline = buffer_init();
53137 - buffer_append_string(cmdline, shell);
53139 + buffer_append_string(cmdline, shell);
53141 + buffer_append_string(cmdline, windir);
53142 + buffer_append_string(cmdline, "\\system32\\cmd.exe");
53144 buffer_append_string_len(cmdline, CONST_STR_LEN(" /c "));
53145 buffer_append_string(cmdline, command);
53146 procok = CreateProcess(NULL, cmdline->ptr, &security, &security, TRUE,
53147 NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
53148 - buffer_free(cmdline);
53150 if (FALSE == procok) {
53151 - fprintf(stderr, "failed to CreateProcess");
53152 + fprintf(stderr, "failed to CreateProcess: %s", cmdline->ptr);
53153 + buffer_free(cmdline);
53156 + buffer_free(cmdline);
53158 proc->child = pi.hProcess;
53159 CloseHandle(pi.hThread);
53160 @@ -226,8 +235,7 @@
53163 if (NULL == (shell = getenv(SHELLENV))) {
53164 - fprintf(stderr, "env %s is required", SHELLENV);
53166 + shell = "/bin/sh";
53169 if (proc_open_pipes(proc) != 0) {
53170 @@ -262,11 +270,11 @@
53174 -#endif /* WIN32 */
53175 +#endif /* _WIN32 */
53177 /* {{{ proc_read_fd_to_buffer */
53178 static void proc_read_fd_to_buffer(int fd, buffer *b) {
53180 + int s; /* win32 has not ssize_t */
53183 buffer_prepare_append(b, 512);
53184 --- ../lighttpd-1.4.11/src/proc_open.h 2005-08-11 01:26:39.000000000 +0300
53185 +++ lighttpd-1.5.0/src/proc_open.h 2006-07-16 00:26:04.000000000 +0300
53188 #include "buffer.h"
53192 #include <windows.h>
53193 typedef HANDLE descriptor_t;
53194 typedef HANDLE proc_pid_t;
53195 --- ../lighttpd-1.4.11/src/request.c 2006-03-05 11:58:09.000000000 +0200
53196 +++ lighttpd-1.5.0/src/request.c 2006-09-07 00:57:05.000000000 +0300
53198 #include <string.h>
53201 +#include <errno.h>
53203 #include "request.h"
53204 #include "keyvalue.h"
53206 +#include "http_req.h"
53208 -static int request_check_hostname(server *srv, connection *con, buffer *host) {
53209 +#include "sys-strings.h"
53211 +static int request_check_hostname(buffer *host) {
53212 enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
53217 - int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
53218 + int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
53225 * hostport = host [ ":" port ]
53226 @@ -32,17 +33,18 @@
53227 * IPv6address = "[" ... "]"
53233 - if (!host || host->used == 0) return 0;
53235 + if (buffer_is_empty(host)) return 0;
53236 + if (host->used < 1) return 0;
53238 host_len = host->used - 1;
53242 if (host->ptr[0] == '[') {
53243 char *c = host->ptr + 1;
53247 /* check portnumber */
53248 for (; *c && *c != ']'; c++) {
53250 @@ -53,12 +55,12 @@
53263 if (*(c+1) == ':') {
53264 for (c += 2; *c; c++) {
53265 @@ -69,39 +71,39 @@
53271 if (NULL != (colon = memchr(host->ptr, ':', host_len))) {
53272 char *c = colon + 1;
53275 /* check portnumber */
53277 if (!light_isdigit(*c)) return -1;
53281 /* remove the port from the host-len */
53282 host_len = colon - host->ptr;
53286 /* Host is empty */
53287 if (host_len == 0) return -1;
53290 /* scan from the right and skip the \0 */
53291 for (i = host_len - 1; i + 1 > 0; i--) {
53292 const char c = host->ptr[i];
53298 /* only switch stage, if this is not the last character */
53299 if (i != host_len - 1) {
53300 if (label_len == 0) {
53305 /* check the first character at right of the dot */
53307 if (!light_isalpha(host->ptr[i+1])) {
53311 } else if (!light_isdigit(host->ptr[i+1])) {
53313 @@ -111,9 +113,9 @@
53319 stage = DOMAINLABEL;
53324 } else if (i == 0) {
53325 @@ -135,7 +137,7 @@
53334 @@ -143,7 +145,7 @@
53335 if (label_len == 0) {
53342 } else if (!light_isdigit(c)) {
53343 @@ -156,12 +158,12 @@
53344 if (label_len == 0) {
53349 /* c is either - or alphanum here */
53350 if ('-' == host->ptr[i+1]) {
53357 } else if (i == 0) {
53358 @@ -176,20 +178,20 @@
53369 /* a IP has to consist of 4 parts */
53370 if (is_ip == 1 && level != 3) {
53375 if (label_len == 0) {
53383 @@ -201,53 +203,53 @@
53393 * val1, val2, val3, val4
53396 * into a array (more or less a explode() incl. striping of whitespaces
53400 if (b->used == 0) return 0;
53406 for (i =0; i < b->used - 1; ) {
53407 char *start = NULL, *end = NULL;
53416 for (; (*s == ' ' || *s == '\t') && i < b->used - 1; i++, s++);
53423 case 1: /* value */
53427 for (; *s != ',' && i < b->used - 1; i++, s++);
53431 for (; (*end == ' ' || *end == '\t') && end > start; end--);
53434 if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
53435 ds = data_string_init();
53438 buffer_copy_string_len(ds->value, start, end-start+1);
53439 array_insert_unique(vals, (data_unset *)ds);
53447 /* end of string */
53453 @@ -263,747 +265,239 @@
53454 if (c <= 32) return 0;
53455 if (c == 127) return 0;
53456 if (c == 255) return 0;
53462 -int http_request_parse(server *srv, connection *con) {
53463 - char *uri = NULL, *proto = NULL, *method = NULL, con_length_set;
53464 - int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding;
53465 - char *value = NULL, *key = NULL;
53467 - enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_KEEPALIVE, HTTP_CONNECTION_CLOSE } keep_alive_set = HTTP_CONNECTION_UNSET;
53471 - int request_line_stage = 0;
53476 - data_string *ds = NULL;
53479 - * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
53480 - * Option : "^([-a-zA-Z]+): (.+)$"
53483 +int http_request_parse(server *srv, connection *con, http_req *req) {
53485 + enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_CLOSE, HTTP_CONNECTION_KEEPALIVE } keep_alive_set = HTTP_CONNECTION_UNSET;
53487 - if (con->conf.log_request_header) {
53488 - log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
53490 - "request-len:", con->request.request->used,
53491 - "\n", con->request.request);
53492 + if (req->protocol == HTTP_VERSION_UNSET) {
53493 + con->http_status = 505; /* Version not Supported */
53497 - if (con->request_count > 1 &&
53498 - con->request.request->ptr[0] == '\r' &&
53499 - con->request.request->ptr[1] == '\n') {
53500 - /* we are in keep-alive and might get \r\n after a previous POST request.*/
53502 - buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, con->request.request->used - 1 - 2);
53504 - /* fill the local request buffer */
53505 - buffer_copy_string_buffer(con->parse_request, con->request.request);
53506 + if (req->method == HTTP_METHOD_UNSET) {
53507 + con->http_status = 405; /* Method not allowed */
53511 - keep_alive_set = 0;
53512 - con_length_set = 0;
53514 - /* parse the first line of the request
53518 - * <method> <uri> <protocol>\r\n
53519 + if (buffer_is_empty(req->uri_raw)) {
53520 + con->http_status = 400;
53524 + /* strip absolute URLs
53526 - for (i = 0, first = 0; i < con->parse_request->used && line == 0; i++) {
53527 - char *cur = con->parse_request->ptr + i;
53529 + buffer_copy_string_buffer(con->request.orig_uri, req->uri_raw);
53530 + if (req->uri_raw->ptr[0] == '/') {
53531 + buffer_copy_string_buffer(con->request.uri, req->uri_raw);
53532 + } else if (req->uri_raw->ptr[0] == '*') {
53533 + if (req->method != HTTP_METHOD_OPTIONS) {
53534 + con->http_status = 400;
53537 + buffer_copy_string_buffer(con->request.uri, req->uri_raw);
53539 + /* GET http://www.example.org/foobar */
53542 + if (0 != strncmp(BUF_STR(req->uri_raw), "http://", 7)) {
53543 + con->http_status = 400;
53547 + if (NULL == (sl = strchr(BUF_STR(req->uri_raw) + 7, '/'))) {
53548 + con->http_status = 400;
53554 - if (con->parse_request->ptr[i+1] == '\n') {
53556 - char *nuri = NULL;
53559 - /* \r\n -> \0\0 */
53560 - con->parse_request->ptr[i] = '\0';
53561 - con->parse_request->ptr[i+1] = '\0';
53563 - buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
53565 - if (request_line_stage != 2) {
53566 - con->http_status = 400;
53567 - con->response.keep_alive = 0;
53568 - con->keep_alive = 0;
53570 - if (srv->srvconf.log_request_header_on_error) {
53571 - log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
53572 - log_error_write(srv, __FILE__, __LINE__, "Sb",
53573 - "request-header:\n",
53574 - con->request.request);
53579 - proto = con->parse_request->ptr + first;
53581 - *(uri - 1) = '\0';
53582 - *(proto - 1) = '\0';
53584 - /* we got the first one :) */
53585 - if (-1 == (r = get_http_method_key(method))) {
53586 - con->http_status = 501;
53587 - con->response.keep_alive = 0;
53588 - con->keep_alive = 0;
53590 - if (srv->srvconf.log_request_header_on_error) {
53591 - log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
53592 - log_error_write(srv, __FILE__, __LINE__, "Sb",
53593 - "request-header:\n",
53594 - con->request.request);
53598 + buffer_copy_string(con->request.uri, sl);
53599 + buffer_copy_string_len(con->request.http_host, BUF_STR(req->uri_raw) + 7, sl - BUF_STR(req->uri_raw) - 7);
53602 + con->request.http_method = req->method;
53603 + con->request.http_version = req->protocol;
53605 + for (i = 0; i < req->headers->used; i++) {
53606 + data_string *ds = (data_string *)req->headers->data[i];
53607 + data_string *hdr;
53610 + /* this list is sorted */
53611 + if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
53614 + /* Connection: Keep-Alive, ... */
53616 + vals = srv->split_vals;
53618 + array_reset(vals);
53619 + http_request_split_value(vals, ds->value);
53621 + for (vi = 0; vi < vals->used; vi++) {
53622 + data_string *dsv = (data_string *)vals->data[vi];
53624 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
53625 + keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
53628 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
53629 + keep_alive_set = HTTP_CONNECTION_CLOSE;
53634 - con->request.http_method = r;
53639 - * HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
53642 - if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) {
53643 - char * major = proto + sizeof("HTTP/") - 1;
53644 - char * minor = strchr(major, '.');
53645 - char *err = NULL;
53646 - int major_num = 0, minor_num = 0;
53648 - int invalid_version = 0;
53650 - if (NULL == minor || /* no dot */
53651 - minor == major || /* no major */
53652 - *(minor + 1) == '\0' /* no minor */) {
53653 - invalid_version = 1;
53656 - major_num = strtol(major, &err, 10);
53658 + } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
53662 - if (*err != '\0') invalid_version = 1;
53663 + /* ignore the header, if it is a duplicate */
53664 + if (con->request.content_length != -1) continue;
53667 - minor_num = strtol(minor, &err, 10);
53668 + r = strtoll(ds->value->ptr, &err, 10);
53670 - if (*err != '\0') invalid_version = 1;
53672 + if (*err != '\0') {
53673 + TRACE("content-length is not a number: %s (Status: 400)", err);
53675 - if (invalid_version) {
53676 - con->http_status = 400;
53677 - con->keep_alive = 0;
53679 - if (srv->srvconf.log_request_header_on_error) {
53680 - log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
53681 - log_error_write(srv, __FILE__, __LINE__, "Sb",
53682 - "request-header:\n",
53683 - con->request.request);
53687 + con->http_status = 400;
53689 - if (major_num == 1 && minor_num == 1) {
53690 - con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0;
53691 - } else if (major_num == 1 && minor_num == 0) {
53692 - con->request.http_version = HTTP_VERSION_1_0;
53694 - con->http_status = 505;
53696 - if (srv->srvconf.log_request_header_on_error) {
53697 - log_error_write(srv, __FILE__, __LINE__, "s", "unknown HTTP version -> 505");
53698 - log_error_write(srv, __FILE__, __LINE__, "Sb",
53699 - "request-header:\n",
53700 - con->request.request);
53705 - con->http_status = 400;
53706 - con->keep_alive = 0;
53710 + if (r == LLONG_MIN ||
53711 + r == LLONG_MAX) {
53712 + if (errno == ERANGE) {
53713 + con->http_status = 413;
53715 - if (srv->srvconf.log_request_header_on_error) {
53716 - log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
53717 - log_error_write(srv, __FILE__, __LINE__, "Sb",
53718 - "request-header:\n",
53719 - con->request.request);
53724 - if (0 == strncmp(uri, "http://", 7) &&
53725 - NULL != (nuri = strchr(uri + 7, '/'))) {
53726 - /* ignore the host-part */
53728 - buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
53730 - /* everything looks good so far */
53731 - buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
53734 - /* check uri for invalid characters */
53735 - for (j = 0; j < con->request.uri->used - 1; j++) {
53736 - if (!request_uri_is_valid_char(con->request.uri->ptr[j])) {
53737 - unsigned char buf[2];
53738 - con->http_status = 400;
53739 - con->keep_alive = 0;
53741 - if (srv->srvconf.log_request_header_on_error) {
53742 - buf[0] = con->request.uri->ptr[j];
53745 - if (con->request.uri->ptr[j] > 32 &&
53746 - con->request.uri->ptr[j] != 127) {
53747 - /* the character is printable -> print it */
53748 - log_error_write(srv, __FILE__, __LINE__, "ss",
53749 - "invalid character in URI -> 400",
53752 - /* a control-character, print ascii-code */
53753 - log_error_write(srv, __FILE__, __LINE__, "sd",
53754 - "invalid character in URI -> 400",
53755 - con->request.uri->ptr[j]);
53758 - log_error_write(srv, __FILE__, __LINE__, "Sb",
53759 - "request-header:\n",
53760 - con->request.request);
53767 - buffer_copy_string_buffer(con->request.orig_uri, con->request.uri);
53769 - con->http_status = 0;
53777 - switch(request_line_stage) {
53779 - /* GET|POST|... */
53780 - method = con->parse_request->ptr + first;
53784 - /* /foobar/... */
53785 - uri = con->parse_request->ptr + first;
53789 - /* ERROR, one space to much */
53792 con->http_status = 400;
53793 - con->response.keep_alive = 0;
53794 - con->keep_alive = 0;
53796 - if (srv->srvconf.log_request_header_on_error) {
53797 - log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
53798 - log_error_write(srv, __FILE__, __LINE__, "Sb",
53799 - "request-header:\n",
53800 - con->request.request);
53806 - request_line_stage++;
53813 - if (con->request.uri->used == 1) {
53814 - con->http_status = 400;
53815 - con->response.keep_alive = 0;
53816 - con->keep_alive = 0;
53817 + /* don't handle more the SSIZE_MAX bytes in content-length */
53818 + if (r > SSIZE_MAX) {
53819 + con->http_status = 413;
53821 - log_error_write(srv, __FILE__, __LINE__, "s", "no uri specified -> 400");
53822 - if (srv->srvconf.log_request_header_on_error) {
53823 - log_error_write(srv, __FILE__, __LINE__, "Sb",
53824 - "request-header:\n",
53825 - con->request.request);
53829 + ERROR("request-size too long: %s (Status: 413)", BUF_STR(ds->value));
53832 - for (; i < con->parse_request->used && !done; i++) {
53833 - char *cur = con->parse_request->ptr + i;
53837 - int got_colon = 0;
53840 - * 1*<any CHAR except CTLs or separators>
53841 - * CTLs == 0-31 + 127
53846 + con->request.content_length = r;
53847 + } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
53848 + /* HTTP 2616 8.2.3
53849 + * Expect: 100-continue
53851 + * -> (10.1.1) 100 (read content, process request, send final status-code)
53852 + * -> (10.4.18) 417 (close)
53862 - if (is_ws_after_key == 0) {
53863 - key_len = i - first;
53865 - is_ws_after_key = 0;
53885 + if (0 != buffer_caseless_compare(CONST_BUF_LEN(ds->value), CONST_STR_LEN("100-continue"))) {
53886 + /* we only support 100-continue */
53887 + con->http_status = 417;
53891 + if (con->request.http_version != HTTP_VERSION_1_1) {
53892 + /* only HTTP/1.1 clients can send us this header */
53893 + con->http_status = 417;
53896 + } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
53897 + if (request_check_hostname(ds->value)) {
53898 + TRACE("%s", "Host header is invalue (Status: 400)");
53899 con->http_status = 400;
53900 con->keep_alive = 0;
53901 - con->response.keep_alive = 0;
53903 - log_error_write(srv, __FILE__, __LINE__, "sbsds",
53904 - "invalid character in key", con->request.request, cur, *cur, "-> 400");
53909 - if (i == first) {
53918 - key_len = i - first;
53920 - /* skip every thing up to the : */
53921 - for (j = 1; !got_colon; j++) {
53922 - switch(con->parse_request->ptr[j + i]) {
53937 - if (srv->srvconf.log_request_header_on_error) {
53938 - log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
53939 - log_error_write(srv, __FILE__, __LINE__, "Sb",
53940 - "request-header:\n",
53941 - con->request.request);
53944 - con->http_status = 400;
53945 - con->response.keep_alive = 0;
53946 - con->keep_alive = 0;
53954 - if (con->parse_request->ptr[i+1] == '\n' && i == first) {
53955 - /* End of Header */
53956 - con->parse_request->ptr[i] = '\0';
53957 - con->parse_request->ptr[i+1] = '\0';
53965 - if (srv->srvconf.log_request_header_on_error) {
53966 - log_error_write(srv, __FILE__, __LINE__, "s", "CR without LF -> 400");
53967 - log_error_write(srv, __FILE__, __LINE__, "Sb",
53968 - "request-header:\n",
53969 - con->request.request);
53972 - con->http_status = 400;
53973 - con->keep_alive = 0;
53974 - con->response.keep_alive = 0;
53978 - case 0: /* illegal characters (faster than a if () :) */
54011 + if (!buffer_is_empty(con->request.http_host)) {
54012 + TRACE("%s", "Host header is duplicate (Status: 400)");
54013 con->http_status = 400;
54014 - con->keep_alive = 0;
54015 - con->response.keep_alive = 0;
54017 - if (srv->srvconf.log_request_header_on_error) {
54018 - log_error_write(srv, __FILE__, __LINE__, "sbsds",
54019 - "CTL character in key", con->request.request, cur, *cur, "-> 400");
54021 - log_error_write(srv, __FILE__, __LINE__, "Sb",
54022 - "request-header:\n",
54023 - con->request.request);
54034 - if (con->parse_request->ptr[i+1] == '\n') {
54035 - /* End of Headerline */
54036 - con->parse_request->ptr[i] = '\0';
54037 - con->parse_request->ptr[i+1] = '\0';
54039 - if (in_folding) {
54043 - if (srv->srvconf.log_request_header_on_error) {
54044 - log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
54046 - log_error_write(srv, __FILE__, __LINE__, "Sb",
54047 - "request-header:\n",
54048 - con->request.request);
54052 - con->http_status = 400;
54053 - con->keep_alive = 0;
54054 - con->response.keep_alive = 0;
54057 - buffer_append_string(ds->value, value);
54060 - key = con->parse_request->ptr + first;
54062 - s_len = cur - value;
54066 - if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
54067 - ds = data_string_init();
54069 - buffer_copy_string_len(ds->key, key, key_len);
54070 - buffer_copy_string_len(ds->value, value, s_len);
54072 - /* retreive values
54075 - * the list of options is sorted to simplify the search
54078 - if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
54084 - vals = srv->split_vals;
54086 - array_reset(vals);
54088 - http_request_split_value(vals, ds->value);
54090 - for (vi = 0; vi < vals->used; vi++) {
54091 - data_string *dsv = (data_string *)vals->data[vi];
54093 - if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
54094 - keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
54097 - } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
54098 - keep_alive_set = HTTP_CONNECTION_CLOSE;
54104 - } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
54106 - unsigned long int r;
54109 - if (con_length_set) {
54110 - con->http_status = 400;
54111 - con->keep_alive = 0;
54113 - if (srv->srvconf.log_request_header_on_error) {
54114 - log_error_write(srv, __FILE__, __LINE__, "s",
54115 - "duplicate Content-Length-header -> 400");
54116 - log_error_write(srv, __FILE__, __LINE__, "Sb",
54117 - "request-header:\n",
54118 - con->request.request);
54123 - if (ds->value->used == 0) SEGFAULT();
54125 - for (j = 0; j < ds->value->used - 1; j++) {
54126 - char c = ds->value->ptr[j];
54127 - if (!isdigit((unsigned char)c)) {
54128 - log_error_write(srv, __FILE__, __LINE__, "sbs",
54129 - "content-length broken:", ds->value, "-> 400");
54131 - con->http_status = 400;
54132 - con->keep_alive = 0;
54134 - array_insert_unique(con->request.headers, (data_unset *)ds);
54139 - r = strtoul(ds->value->ptr, &err, 10);
54141 - if (*err == '\0') {
54142 - con_length_set = 1;
54143 - con->request.content_length = r;
54145 - log_error_write(srv, __FILE__, __LINE__, "sbs",
54146 - "content-length broken:", ds->value, "-> 400");
54148 - con->http_status = 400;
54149 - con->keep_alive = 0;
54151 - array_insert_unique(con->request.headers, (data_unset *)ds);
54154 - } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Type")))) {
54155 - /* if dup, only the first one will survive */
54156 - if (!con->request.http_content_type) {
54157 - con->request.http_content_type = ds->value->ptr;
54159 - con->http_status = 400;
54160 - con->keep_alive = 0;
54162 - if (srv->srvconf.log_request_header_on_error) {
54163 - log_error_write(srv, __FILE__, __LINE__, "s",
54164 - "duplicate Content-Type-header -> 400");
54165 - log_error_write(srv, __FILE__, __LINE__, "Sb",
54166 - "request-header:\n",
54167 - con->request.request);
54171 - } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
54172 - /* HTTP 2616 8.2.3
54173 - * Expect: 100-continue
54175 - * -> (10.1.1) 100 (read content, process request, send final status-code)
54176 - * -> (10.4.18) 417 (close)
54178 - * (not handled at all yet, we always send 417 here)
54180 - * What has to be added ?
54181 - * 1. handling of chunked request body
54182 - * 2. out-of-order sending from the HTTP/1.1 100 Continue
54187 - con->http_status = 417;
54188 - con->keep_alive = 0;
54190 - array_insert_unique(con->request.headers, (data_unset *)ds);
54192 - } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
54193 - if (!con->request.http_host) {
54194 - con->request.http_host = ds->value;
54196 - con->http_status = 400;
54197 - con->keep_alive = 0;
54199 - if (srv->srvconf.log_request_header_on_error) {
54200 - log_error_write(srv, __FILE__, __LINE__, "s",
54201 - "duplicate Host-header -> 400");
54202 - log_error_write(srv, __FILE__, __LINE__, "Sb",
54203 - "request-header:\n",
54204 - con->request.request);
54208 - } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
54209 - /* Proxies sometimes send dup headers
54210 - * if they are the same we ignore the second
54211 - * if not, we raise an error */
54212 - if (!con->request.http_if_modified_since) {
54213 - con->request.http_if_modified_since = ds->value->ptr;
54214 - } else if (0 == strcasecmp(con->request.http_if_modified_since,
54215 - ds->value->ptr)) {
54216 - /* ignore it if they are the same */
54218 - con->http_status = 400;
54219 - con->keep_alive = 0;
54221 - if (srv->srvconf.log_request_header_on_error) {
54222 - log_error_write(srv, __FILE__, __LINE__, "s",
54223 - "duplicate If-Modified-Since header -> 400");
54224 - log_error_write(srv, __FILE__, __LINE__, "Sb",
54225 - "request-header:\n",
54226 - con->request.request);
54230 - } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
54231 - /* if dup, only the first one will survive */
54232 - if (!con->request.http_if_none_match) {
54233 - con->request.http_if_none_match = ds->value->ptr;
54235 - con->http_status = 400;
54236 - con->keep_alive = 0;
54238 - if (srv->srvconf.log_request_header_on_error) {
54239 - log_error_write(srv, __FILE__, __LINE__, "s",
54240 - "duplicate If-None-Match-header -> 400");
54241 - log_error_write(srv, __FILE__, __LINE__, "Sb",
54242 - "request-header:\n",
54243 - con->request.request);
54247 - } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
54248 - if (!con->request.http_range) {
54249 - /* bytes=.*-.* */
54251 - if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) &&
54252 - NULL != strchr(ds->value->ptr+6, '-')) {
54254 - /* if dup, only the first one will survive */
54255 - con->request.http_range = ds->value->ptr + 6;
54258 - con->http_status = 400;
54259 - con->keep_alive = 0;
54261 - if (srv->srvconf.log_request_header_on_error) {
54262 - log_error_write(srv, __FILE__, __LINE__, "s",
54263 - "duplicate Range-header -> 400");
54264 - log_error_write(srv, __FILE__, __LINE__, "Sb",
54265 - "request-header:\n",
54266 - con->request.request);
54272 - array_insert_unique(con->request.headers, (data_unset *)ds);
54274 - /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
54285 - if (srv->srvconf.log_request_header_on_error) {
54286 - log_error_write(srv, __FILE__, __LINE__, "sbs",
54287 - "CR without LF", con->request.request, "-> 400");
54291 + buffer_copy_string_buffer(con->request.http_host, ds->value);
54292 + } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
54293 + data_string *old;
54295 + if (NULL != (old = (data_string *)array_get_element(con->request.headers, "If-Modified-Since"))) {
54296 + if (0 != buffer_caseless_compare(CONST_BUF_LEN(old->value), CONST_BUF_LEN(ds->value))) {
54297 + /* duplicate header and different timestamps */
54298 con->http_status = 400;
54299 - con->keep_alive = 0;
54300 - con->response.keep_alive = 0;
54302 + TRACE("%s", "If-Modified-Since is duplicate (Status: 400)");
54307 + } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
54308 + data_string *old;
54309 + /* if dup, only the first one will survive */
54310 + if (NULL != (old = (data_string *)array_get_element(con->request.headers, "If-None-Match"))) {
54311 + if (0 != buffer_caseless_compare(CONST_BUF_LEN(old->value), CONST_BUF_LEN(ds->value))) {
54312 + /* duplicate header and different timestamps */
54313 + con->http_status = 400;
54315 + TRACE("%s", "If-None-Match is duplicate (Status: 400)");
54322 - /* strip leading WS */
54323 - if (value == cur) value = cur+1;
54327 + } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
54328 + if (NULL != array_get_element(con->request.headers, "Range")) {
54329 + /* duplicate Range header */
54331 + TRACE("%s", "Range: header is duplicate (Status: 400)");
54333 + con->http_status = 400;
54334 + con->keep_alive = 0;
54340 + hdr = data_string_init();
54342 + buffer_copy_string_buffer(hdr->key, ds->key);
54343 + buffer_copy_string_buffer(hdr->value, ds->value);
54345 + array_insert_unique(con->request.headers, (data_unset *)hdr);
54350 con->header_len = i;
54353 /* do some post-processing */
54355 if (con->request.http_version == HTTP_VERSION_1_1) {
54356 if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
54357 /* no Connection-Header sent */
54360 /* HTTP/1.1 -> keep-alive default TRUE */
54361 con->keep_alive = 1;
54363 con->keep_alive = 0;
54367 /* RFC 2616, 14.23 */
54368 - if (con->request.http_host == NULL ||
54369 - buffer_is_empty(con->request.http_host)) {
54370 + if (buffer_is_empty(con->request.http_host)) {
54371 con->http_status = 400;
54372 con->response.keep_alive = 0;
54373 con->keep_alive = 0;
54376 if (srv->srvconf.log_request_header_on_error) {
54377 log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
54378 log_error_write(srv, __FILE__, __LINE__, "Sb",
54379 @@ -1015,40 +509,21 @@
54381 if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
54382 /* no Connection-Header sent */
54385 /* HTTP/1.0 -> keep-alive default FALSE */
54386 con->keep_alive = 1;
54388 con->keep_alive = 0;
54392 - /* check hostname field if it is set */
54393 - if (NULL != con->request.http_host &&
54394 - 0 != request_check_hostname(srv, con, con->request.http_host)) {
54396 - if (srv->srvconf.log_request_header_on_error) {
54397 - log_error_write(srv, __FILE__, __LINE__, "s",
54398 - "Invalid Hostname -> 400");
54399 - log_error_write(srv, __FILE__, __LINE__, "Sb",
54400 - "request-header:\n",
54401 - con->request.request);
54404 - con->http_status = 400;
54405 - con->response.keep_alive = 0;
54406 - con->keep_alive = 0;
54411 switch(con->request.http_method) {
54412 case HTTP_METHOD_GET:
54413 case HTTP_METHOD_HEAD:
54414 /* content-length is forbidden for those */
54415 - if (con_length_set && con->request.content_length != 0) {
54416 + if (con->request.content_length != -1) {
54417 /* content-length is missing */
54418 - log_error_write(srv, __FILE__, __LINE__, "s",
54419 + log_error_write(srv, __FILE__, __LINE__, "s",
54420 "GET/HEAD with content-length -> 400");
54422 con->keep_alive = 0;
54423 @@ -1058,9 +533,9 @@
54425 case HTTP_METHOD_POST:
54426 /* content-length is required for them */
54427 - if (!con_length_set) {
54428 + if (con->request.content_length == -1) {
54429 /* content-length is missing */
54430 - log_error_write(srv, __FILE__, __LINE__, "s",
54431 + log_error_write(srv, __FILE__, __LINE__, "s",
54432 "POST-request, but content-length missing -> 411");
54434 con->keep_alive = 0;
54435 @@ -1073,52 +548,27 @@
54436 /* the may have a content-length */
54441 - /* check if we have read post data */
54442 - if (con_length_set) {
54443 - /* don't handle more the SSIZE_MAX bytes in content-length */
54444 - if (con->request.content_length > SSIZE_MAX) {
54445 - con->http_status = 413;
54446 - con->keep_alive = 0;
54448 - log_error_write(srv, __FILE__, __LINE__, "sds",
54449 - "request-size too long:", con->request.content_length, "-> 413");
54453 + /* check if we have read post data */
54454 + if (con->request.content_length != -1) {
54455 /* divide by 1024 as srvconf.max_request_size is in kBytes */
54456 if (srv->srvconf.max_request_size != 0 &&
54457 (con->request.content_length >> 10) > srv->srvconf.max_request_size) {
54458 - /* the request body itself is larger then
54459 + /* the request body itself is larger then
54460 * our our max_request_size
54464 con->http_status = 413;
54465 con->keep_alive = 0;
54467 - log_error_write(srv, __FILE__, __LINE__, "sds",
54469 + log_error_write(srv, __FILE__, __LINE__, "sds",
54470 "request-size too long:", con->request.content_length, "-> 413");
54475 - /* we have content */
54476 - if (con->request.content_length != 0) {
54485 -int http_request_header_finished(server *srv, connection *con) {
54488 - if (con->request.request->used < 5) return 0;
54490 - if (0 == memcmp(con->request.request->ptr + con->request.request->used - 5, "\r\n\r\n", 4)) return 1;
54491 - if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1;
54495 --- ../lighttpd-1.4.11/src/request.h 2005-08-11 01:26:40.000000000 +0300
54496 +++ lighttpd-1.5.0/src/request.h 2006-09-07 00:57:05.000000000 +0300
54498 #ifndef _REQUEST_H_
54499 #define _REQUEST_H_
54501 -#include "server.h"
54503 +#include "http_req.h"
54505 -int http_request_parse(server *srv, connection *con);
54506 -int http_request_header_finished(server *srv, connection *con);
54507 +int http_request_parse(server *srv, connection *con, http_req *req);
54510 --- ../lighttpd-1.4.11/src/response.c 2006-03-04 16:41:39.000000000 +0200
54511 +++ lighttpd-1.5.0/src/response.c 2006-09-07 00:57:05.000000000 +0300
54513 #include <stdlib.h>
54514 #include <string.h>
54516 -#include <unistd.h>
54518 #include <assert.h>
54520 @@ -24,15 +23,17 @@
54521 #include "plugin.h"
54523 #include "sys-socket.h"
54524 +#include "sys-files.h"
54525 +#include "sys-strings.h"
54527 -int http_response_write_header(server *srv, connection *con) {
54528 +int http_response_write_header(server *srv, connection *con, chunkqueue *raw) {
54532 int have_server = 0;
54534 - b = chunkqueue_get_prepend_buffer(con->write_queue);
54537 + b = chunkqueue_get_prepend_buffer(raw);
54539 if (con->request.http_version == HTTP_VERSION_1_1) {
54540 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
54542 @@ -41,25 +42,26 @@
54543 buffer_append_long(b, con->http_status);
54544 BUFFER_APPEND_STRING_CONST(b, " ");
54545 buffer_append_string(b, get_http_status_name(con->http_status));
54548 if (con->request.http_version != HTTP_VERSION_1_1 || con->keep_alive == 0) {
54549 BUFFER_APPEND_STRING_CONST(b, "\r\nConnection: ");
54550 buffer_append_string(b, con->keep_alive ? "keep-alive" : "close");
54554 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
54555 BUFFER_APPEND_STRING_CONST(b, "\r\nTransfer-Encoding: chunked");
54561 /* add all headers */
54562 for (i = 0; i < con->response.headers->used; i++) {
54566 ds = (data_string *)con->response.headers->data[i];
54569 if (ds->value->used && ds->key->used &&
54570 - 0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1)) {
54571 + 0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1) &&
54572 + 0 != strcasecmp(ds->key->ptr, "X-Sendfile")) {
54573 if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Date"))) have_date = 1;
54574 if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Server"))) have_server = 1;
54576 @@ -68,28 +70,28 @@
54577 BUFFER_APPEND_STRING_CONST(b, ": ");
54578 buffer_append_string_buffer(b, ds->value);
54580 - log_error_write(srv, __FILE__, __LINE__, "bb",
54581 + log_error_write(srv, __FILE__, __LINE__, "bb",
54582 ds->key, ds->value);
54589 /* HTTP/1.1 requires a Date: header */
54590 BUFFER_APPEND_STRING_CONST(b, "\r\nDate: ");
54593 /* cache the generated timestamp */
54594 if (srv->cur_ts != srv->last_generated_date_ts) {
54595 buffer_prepare_copy(srv->ts_date_str, 255);
54597 - strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
54599 + strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
54600 "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts)));
54603 srv->ts_date_str->used = strlen(srv->ts_date_str->ptr) + 1;
54606 srv->last_generated_date_ts = srv->cur_ts;
54610 buffer_append_string_buffer(b, srv->ts_date_str);
54613 @@ -101,88 +103,85 @@
54614 buffer_append_string_buffer(b, con->conf.server_tag);
54619 BUFFER_APPEND_STRING_CONST(b, "\r\n\r\n");
54624 con->bytes_header = b->used - 1;
54627 if (con->conf.log_response_header) {
54628 log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b);
54637 -handler_t http_response_prepare(server *srv, connection *con) {
54638 +handler_t handle_get_backend(server *srv, connection *con) {
54641 - /* looks like someone has already done a decision */
54642 - if (con->mode == DIRECT &&
54644 + /* looks like someone has already made a decision */
54645 + if (con->mode == DIRECT &&
54646 (con->http_status != 0 && con->http_status != 200)) {
54647 /* remove a packets in the queue */
54648 - if (con->file_finished == 0) {
54649 - chunkqueue_reset(con->write_queue);
54653 return HANDLER_FINISHED;
54657 /* no decision yet, build conf->filename */
54658 if (con->mode == DIRECT && con->physical.path->used == 0) {
54661 - /* we only come here when we have the parse the full request again
54663 - * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
54664 + /* we only come here when we have to parse the full request again
54666 + * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
54667 * problem here as mod_setenv might get called multiple times
54669 * fastcgi-auth might lead to a COMEBACK too
54670 * fastcgi again dead server too
54672 * mod_compress might add headers twice too
54678 if (con->conf.log_condition_handling) {
54679 log_error_write(srv, __FILE__, __LINE__, "s", "run condition");
54681 config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */
54690 * - uri.path (secure)
54699 * Name according to RFC 2396
54708 * (scheme)://(authority)(path)?(query)
54716 buffer_copy_string(con->uri.scheme, con->conf.is_ssl ? "https" : "http");
54717 buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
54718 buffer_to_lower(con->uri.authority);
54721 config_patch_connection(srv, con, COMP_HTTP_HOST); /* Host: */
54722 config_patch_connection(srv, con, COMP_HTTP_REMOTEIP); /* Client-IP */
54723 config_patch_connection(srv, con, COMP_HTTP_REFERER); /* Referer: */
54724 config_patch_connection(srv, con, COMP_HTTP_USERAGENT); /* User-Agent: */
54725 config_patch_connection(srv, con, COMP_HTTP_COOKIE); /* Cookie: */
54728 /** extract query string from request.uri */
54729 if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) {
54730 buffer_copy_string (con->uri.query, qstr + 1);
54731 @@ -200,22 +199,22 @@
54732 log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path : ", con->uri.path_raw);
54733 log_error_write(srv, __FILE__, __LINE__, "sb", "URI-query : ", con->uri.query);
54737 /* disable keep-alive if requested */
54740 if (con->request_count > con->conf.max_keep_alive_requests) {
54741 con->keep_alive = 0;
54754 * - based on the raw URL
54760 switch(r = plugins_call_handle_uri_raw(srv, con)) {
54761 case HANDLER_GO_ON:
54763 @@ -229,14 +228,14 @@
54767 - /* build filename
54768 + /* build filename
54770 * - decode url-encodings (e.g. %20 -> ' ')
54771 * - remove path-modifiers (e.g. /../)
54779 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
54780 con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
54781 /* OPTIONS * ... */
54782 @@ -253,15 +252,21 @@
54792 * - based on the clean URL
54798 config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */
54800 + config_patch_connection(srv, con, COMP_HTTP_QUERYSTRING); /* HTTPqs */
54802 + /* do we have to downgrade to 1.0 ? */
54803 + if (!con->conf.allow_http11) {
54804 + con->request.http_version = HTTP_VERSION_1_0;
54807 switch(r = plugins_call_handle_uri_clean(srv, con)) {
54808 case HANDLER_GO_ON:
54810 @@ -274,60 +279,62 @@
54811 log_error_write(srv, __FILE__, __LINE__, "");
54816 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
54817 con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
54818 - /* option requests are handled directly without checking of the path */
54820 + /* option requests are handled directly without checking the path */
54822 response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
54824 con->http_status = 200;
54825 - con->file_finished = 1;
54826 + /* no more content to send */
54827 + con->send->is_closed = 1;
54829 return HANDLER_FINISHED;
54839 * logical filename (URI) becomes a physical filename here
54856 * ... ISREG() -> ok, go on
54857 * ... ISDIR() -> index-file -> redirect
54872 * SEARCH DOCUMENT ROOT
54876 /* set a default */
54879 buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root);
54880 buffer_copy_string_buffer(con->physical.rel_path, con->uri.path);
54882 -#if defined(__WIN32) || defined(__CYGWIN__)
54883 - /* strip dots from the end and spaces
54885 + filename_unix2local(con->physical.rel_path);
54886 +#if defined(_WIN32) || defined(__CYGWIN__)
54887 + /* strip dots and spaces from the end
54889 * windows/dos handle those filenames as the same file
54891 * foo == foo. == foo..... == "foo... " == "foo.. ./"
54893 - * This will affect in some cases PATHINFO
54894 + * This will affect PATHINFO in some cases
54896 * on native windows we could prepend the filename with \\?\ to circumvent
54897 * this behaviour. I have no idea how to push this through cygwin
54898 @@ -377,36 +384,41 @@
54899 log_error_write(srv, __FILE__, __LINE__, "");
54903 - /* MacOS X and Windows can't distiguish between upper and lower-case
54905 - * convert to lower-case
54907 + /* The default Mac OS X and Windows filesystems can't distiguish between
54908 + * upper- and lowercase, so convert to lowercase
54910 if (con->conf.force_lowercase_filenames) {
54911 buffer_to_lower(con->physical.rel_path);
54914 - /* the docroot plugins might set the servername, if they don't we take http-host */
54915 + /* the docroot plugins might set the servername; if they don't we take http-host */
54916 if (buffer_is_empty(con->server_name)) {
54917 buffer_copy_string_buffer(con->server_name, con->uri.authority);
54921 - * create physical filename
54924 + * create physical filename
54925 * -> physical.path = docroot + rel_path
54931 buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
54932 - BUFFER_APPEND_SLASH(con->physical.path);
54933 + PATHNAME_APPEND_SLASH(con->physical.path);
54934 buffer_copy_string_buffer(con->physical.basedir, con->physical.path);
54935 if (con->physical.rel_path->used &&
54936 - con->physical.rel_path->ptr[0] == '/') {
54937 + con->physical.rel_path->ptr[0] == DIR_SEPERATOR) {
54938 buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2);
54940 buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
54943 + /* win32: directories can't have a trailing slash */
54944 + if (con->physical.path->ptr[con->physical.path->used - 2] == DIR_SEPERATOR) {
54945 + con->physical.path->ptr[con->physical.path->used - 2] = '\0';
54946 + con->physical.path->used--;
54949 if (con->conf.log_request_handling) {
54950 log_error_write(srv, __FILE__, __LINE__, "s", "-- after doc_root");
54951 log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root);
54952 @@ -426,7 +438,7 @@
54953 log_error_write(srv, __FILE__, __LINE__, "");
54958 if (con->conf.log_request_handling) {
54959 log_error_write(srv, __FILE__, __LINE__, "s", "-- logical -> physical");
54960 log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root);
54961 @@ -434,41 +446,60 @@
54962 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
54967 - * Noone catched away the file from normal path of execution yet (like mod_access)
54970 + * No one took the file away from the normal path of execution yet (like mod_access)
54972 + * we don't have a backend yet, try to resolve the physical path and go on
54974 - * Go on and check of the file exists at all
54978 if (con->mode == DIRECT) {
54979 char *slash = NULL;
54980 char *pathinfo = NULL;
54982 stat_cache_entry *sce = NULL;
54985 if (con->conf.log_request_handling) {
54986 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling physical path");
54987 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
54991 if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
54995 if (con->conf.log_request_handling) {
54996 log_error_write(srv, __FILE__, __LINE__, "s", "-- file found");
54997 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
55002 + if ((sce->is_symlink != 0) && !con->conf.follow_symlink) {
55003 + con->http_status = 403;
55005 + if (con->conf.log_request_handling) {
55006 + log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied due symlink restriction");
55007 + log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
55010 + buffer_reset(con->physical.path);
55011 + return HANDLER_FINISHED;
55015 if (S_ISDIR(sce->st.st_mode)) {
55016 - if (con->physical.path->ptr[con->physical.path->used - 2] != '/') {
55017 + if (con->uri.path->ptr[con->uri.path->used - 2] != '/') {
55018 /* redirect to .../ */
55021 http_response_redirect_to_directory(srv, con);
55024 return HANDLER_FINISHED;
55027 + } else if (!S_ISREG(sce->st.st_mode) && !sce->is_symlink) {
55029 } else if (!S_ISREG(sce->st.st_mode)) {
55031 /* any special handling of non-reg files ?*/
55034 @@ -477,12 +508,12 @@
55037 con->http_status = 403;
55040 if (con->conf.log_request_handling) {
55041 log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied");
55042 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
55046 buffer_reset(con->physical.path);
55047 return HANDLER_FINISHED;
55049 @@ -499,77 +530,77 @@
55050 /* PATH_INFO ! :) */
55053 - /* we have no idea what happend. let's tell the user so. */
55054 + /* we have no idea what happened, so tell the user. */
55055 con->http_status = 500;
55056 buffer_reset(con->physical.path);
55059 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
55060 "file not found ... or so: ", strerror(errno),
55062 "->", con->physical.path);
55065 return HANDLER_FINISHED;
55069 /* not found, perhaps PATHINFO */
55072 buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
55080 buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr);
55082 buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
55086 if (0 == stat(con->physical.path->ptr, &(st)) &&
55087 S_ISREG(st.st_mode)) {
55093 if (pathinfo != NULL) {
55096 slash = strrchr(srv->tmp_buf->ptr, '/');
55099 if (pathinfo != NULL) {
55105 if (slash) pathinfo = slash;
55106 } while ((found == 0) && (slash != NULL) && (slash - srv->tmp_buf->ptr > con->physical.basedir->used - 2));
55110 - /* no it really doesn't exists */
55111 + /* no, it really doesn't exists */
55112 con->http_status = 404;
55115 if (con->conf.log_file_not_found) {
55116 log_error_write(srv, __FILE__, __LINE__, "sbsb",
55117 "file not found:", con->uri.path,
55118 "->", con->physical.path);
55122 buffer_reset(con->physical.path);
55125 return HANDLER_FINISHED;
55129 /* we have a PATHINFO */
55131 buffer_copy_string(con->request.pathinfo, pathinfo);
55139 con->uri.path->used -= strlen(pathinfo);
55140 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
55144 if (con->conf.log_request_handling) {
55145 log_error_write(srv, __FILE__, __LINE__, "s", "-- after pathinfo check");
55146 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
55147 @@ -577,50 +608,37 @@
55148 log_error_write(srv, __FILE__, __LINE__, "sb", "Pathinfo :", con->request.pathinfo);
55153 if (con->conf.log_request_handling) {
55154 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling subrequest");
55155 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
55159 /* call the handlers */
55160 - switch(r = plugins_call_handle_subrequest_start(srv, con)) {
55161 + switch(r = plugins_call_handle_start_backend(srv, con)) {
55162 case HANDLER_GO_ON:
55163 - /* request was not handled */
55165 case HANDLER_FINISHED:
55166 + /* if we are still here, no one wanted the file; status 403 is ok I think */
55169 if (con->conf.log_request_handling) {
55170 log_error_write(srv, __FILE__, __LINE__, "s", "-- subrequest finished");
55173 - /* something strange happend */
55175 + /* something strange happened */
55179 - /* if we are still here, no one wanted the file, status 403 is ok I think */
55181 - if (con->mode == DIRECT) {
55182 - con->http_status = 403;
55184 - return HANDLER_FINISHED;
55189 - switch(r = plugins_call_handle_subrequest(srv, con)) {
55190 - case HANDLER_GO_ON:
55191 - /* request was not handled, looks like we are done */
55193 + if (con->mode == DIRECT) {
55194 + con->http_status = 403;
55196 + TRACE("%s", "aaaaaaah, sending 403");
55198 return HANDLER_FINISHED;
55199 - case HANDLER_FINISHED:
55200 - /* request is finished */
55202 - /* something strange happend */
55206 - /* can't happen */
55207 - return HANDLER_COMEBACK;
55209 + return HANDLER_GO_ON;
55214 --- ../lighttpd-1.4.11/src/response.h 2005-08-31 16:25:50.000000000 +0300
55215 +++ lighttpd-1.5.0/src/response.h 2006-09-07 00:57:05.000000000 +0300
55217 #include "server.h"
55219 int http_response_parse(server *srv, connection *con);
55220 -int http_response_write_header(server *srv, connection *con);
55221 +int http_response_write_header(server *srv, connection *con, chunkqueue *cq);
55223 int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen);
55224 int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen);
55226 -handler_t http_response_prepare(server *srv, connection *con);
55227 +handler_t handle_get_backend(server *srv, connection *con);
55228 int http_response_redirect_to_directory(server *srv, connection *con);
55229 int http_response_handle_cachable(server *srv, connection *con, buffer * mtime);
55231 --- ../lighttpd-1.4.11/src/server.c 2006-03-04 19:12:17.000000000 +0200
55232 +++ lighttpd-1.5.0/src/server.c 2006-09-07 00:57:05.000000000 +0300
55234 #include <sys/types.h>
55235 -#include <sys/time.h>
55236 #include <sys/stat.h>
55238 #include <string.h>
55241 -#include <unistd.h>
55242 #include <stdlib.h>
55244 #include <signal.h>
55245 @@ -22,16 +20,21 @@
55246 #include "response.h"
55247 #include "request.h"
55249 -#include "http_chunk.h"
55250 #include "fdevent.h"
55251 #include "connections.h"
55252 #include "stat_cache.h"
55253 #include "plugin.h"
55254 #include "joblist.h"
55255 #include "network_backends.h"
55257 +#include "status_counter.h"
55259 +/* use local getopt implementation */
55260 +# undef HAVE_GETOPT_H
55262 #ifdef HAVE_GETOPT_H
55263 #include <getopt.h>
55265 +#include "getopt.h"
55268 #ifdef HAVE_VALGRIND_VALGRIND_H
55270 /* #define USE_ALARM */
55274 +#undef HAVE_SIGNAL
55277 +#include "sys-files.h"
55278 +#include "sys-process.h"
55279 +#include "sys-socket.h"
55281 static volatile sig_atomic_t srv_shutdown = 0;
55282 static volatile sig_atomic_t graceful_shutdown = 0;
55283 +static volatile sig_atomic_t graceful_restart = 0;
55284 static volatile sig_atomic_t handle_sig_alarm = 1;
55285 static volatile sig_atomic_t handle_sig_hup = 0;
55290 case SIGTERM: srv_shutdown = 1; break;
55293 if (graceful_shutdown) srv_shutdown = 1;
55294 - else graceful_shutdown = 1;
55295 + else graceful_shutdown = 1;
55298 case SIGALRM: handle_sig_alarm = 1; break;
55300 static void signal_handler(int sig) {
55302 case SIGTERM: srv_shutdown = 1; break;
55305 if (graceful_shutdown) srv_shutdown = 1;
55306 - else graceful_shutdown = 1;
55307 + else graceful_shutdown = 1;
55310 case SIGALRM: handle_sig_alarm = 1; break;
55311 @@ -110,35 +122,35 @@
55312 signal(SIGTSTP, SIG_IGN);
55314 if (0 != fork()) exit(0);
55317 if (-1 == setsid()) exit(0);
55319 signal(SIGHUP, SIG_IGN);
55321 if (0 != fork()) exit(0);
55324 if (0 != chdir("/")) exit(0);
55328 static server *server_init(void) {
55332 server *srv = calloc(1, sizeof(*srv));
55334 + srv->max_fds = 1024;
55336 srv->x = buffer_init();
55339 CLEAN(response_header);
55340 CLEAN(parse_full_path);
55341 CLEAN(ts_debug_str);
55342 CLEAN(ts_date_str);
55343 - CLEAN(errorlog_buf);
55344 CLEAN(response_range);
55346 srv->empty_string = buffer_init_string("");
55347 CLEAN(cond_check_buf);
55350 CLEAN(srvconf.errorlog_file);
55351 CLEAN(srvconf.groupname);
55352 CLEAN(srvconf.username);
55353 @@ -146,68 +158,62 @@
55354 CLEAN(srvconf.bindhost);
55355 CLEAN(srvconf.event_handler);
55356 CLEAN(srvconf.pid_file);
55359 CLEAN(tmp_chunk_len);
55364 srv->x = array_init();
55367 CLEAN(config_context);
55368 CLEAN(config_touched);
55373 for (i = 0; i < FILE_CACHE_MAX; i++) {
55374 srv->mtime_cache[i].str = buffer_init();
55378 srv->cur_ts = time(NULL);
55379 srv->startup_ts = srv->cur_ts;
55382 srv->conns = calloc(1, sizeof(*srv->conns));
55383 assert(srv->conns);
55386 srv->joblist = calloc(1, sizeof(*srv->joblist));
55387 assert(srv->joblist);
55390 srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue));
55391 assert(srv->fdwaitqueue);
55394 srv->srvconf.modules = array_init();
55395 srv->srvconf.modules_dir = buffer_init_string(LIBRARY_DIR);
55396 srv->srvconf.network_backend = buffer_init();
55397 srv->srvconf.upload_tempdirs = array_init();
55400 - srv->errorlog_fd = -1;
55401 - srv->errorlog_mode = ERRORLOG_STDERR;
55403 srv->split_vals = array_init();
55409 static void server_free(server *srv) {
55413 for (i = 0; i < FILE_CACHE_MAX; i++) {
55414 buffer_free(srv->mtime_cache[i].str);
55419 buffer_free(srv->x);
55422 CLEAN(response_header);
55423 CLEAN(parse_full_path);
55424 CLEAN(ts_debug_str);
55425 CLEAN(ts_date_str);
55426 - CLEAN(errorlog_buf);
55427 CLEAN(response_range);
55429 CLEAN(empty_string);
55430 CLEAN(cond_check_buf);
55433 CLEAN(srvconf.errorlog_file);
55434 CLEAN(srvconf.groupname);
55435 CLEAN(srvconf.username);
55436 @@ -217,7 +223,7 @@
55437 CLEAN(srvconf.pid_file);
55438 CLEAN(srvconf.modules_dir);
55439 CLEAN(srvconf.network_backend);
55442 CLEAN(tmp_chunk_len);
55445 @@ -225,15 +231,15 @@
55446 fdevent_unregister(srv->ev, srv->fd);
55448 fdevent_free(srv->ev);
55454 if (srv->config_storage) {
55455 for (i = 0; i < srv->config_context->used; i++) {
55456 specific_config *s = srv->config_storage[i];
55461 buffer_free(s->document_root);
55462 buffer_free(s->server_name);
55463 buffer_free(s->server_tag);
55464 @@ -242,32 +248,31 @@
55465 buffer_free(s->error_handler);
55466 buffer_free(s->errorfile_prefix);
55467 array_free(s->mimetypes);
55472 free(srv->config_storage);
55473 srv->config_storage = NULL;
55478 array_free(srv->x);
55481 CLEAN(config_context);
55482 CLEAN(config_touched);
55484 CLEAN(srvconf.upload_tempdirs);
55488 joblist_free(srv, srv->joblist);
55489 fdwaitqueue_free(srv, srv->fdwaitqueue);
55492 if (srv->stat_cache) {
55493 stat_cache_free(srv->stat_cache);
55496 array_free(srv->srvconf.modules);
55497 array_free(srv->split_vals);
55503 @@ -281,14 +286,12 @@
55504 " - a light and fast webserver\n" \
55505 "Build-Date: " __DATE__ " " __TIME__ "\n";
55509 write(STDOUT_FILENO, b, strlen(b));
55512 static void show_features (void) {
55514 - printf("\nEvent Handlers:\n\n%s",
55516 + const char *s = ""
55518 "\t+ select (generic)\n"
55520 @@ -355,11 +358,6 @@
55522 "\t- crypt support\n"
55525 - "\t+ PAM support\n"
55527 - "\t- PAM support\n"
55530 "\t+ SSL Support\n"
55532 @@ -371,9 +369,9 @@
55533 "\t- PCRE support\n"
55536 - "\t+ mySQL support\n"
55537 + "\t+ MySQL support\n"
55539 - "\t- mySQL support\n"
55540 + "\t- MySQL support\n"
55542 #if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
55543 "\t+ LDAP support\n"
55544 @@ -410,8 +408,11 @@
55546 "\t- GDBM support\n"
55554 + printf("\nEvent Handlers:\n\n%s", s);
55557 static void show_help (void) {
55558 @@ -433,197 +434,570 @@
55559 " -h show this help\n" \
55565 write(STDOUT_FILENO, b, strlen(b));
55568 -int main (int argc, char **argv) {
55569 - server *srv = NULL;
55570 - int print_config = 0;
55571 - int test_config = 0;
55574 - int num_childs = 0;
55575 - int pid_fd = -1, fd;
55577 -#ifdef HAVE_SIGACTION
55578 - struct sigaction act;
55580 -#ifdef HAVE_GETRLIMIT
55581 - struct rlimit rlim;
55585 - struct itimerval interval;
55587 - interval.it_interval.tv_sec = 1;
55588 - interval.it_interval.tv_usec = 0;
55589 - interval.it_value.tv_sec = 1;
55590 - interval.it_value.tv_usec = 0;
55594 - /* for nice %b handling in strfime() */
55595 - setlocale(LC_TIME, "C");
55597 - if (NULL == (srv = server_init())) {
55598 - fprintf(stderr, "did this really happen?\n");
55602 - /* init structs done */
55604 - srv->srvconf.port = 0;
55605 -#ifdef HAVE_GETUID
55606 - i_am_root = (getuid() == 0);
55610 - srv->srvconf.dont_daemonize = 0;
55612 - while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
55615 - if (config_read(srv, optarg)) {
55616 - server_free(srv);
55621 - buffer_copy_string(srv->srvconf.modules_dir, optarg);
55623 - case 'p': print_config = 1; break;
55624 - case 't': test_config = 1; break;
55625 - case 'D': srv->srvconf.dont_daemonize = 1; break;
55626 - case 'v': show_version(); return 0;
55627 - case 'V': show_features(); return 0;
55628 - case 'h': show_help(); return 0;
55631 - server_free(srv);
55636 - if (!srv->config_storage) {
55637 - log_error_write(srv, __FILE__, __LINE__, "s",
55638 - "No configuration available. Try using -f option.");
55640 - server_free(srv);
55644 - if (print_config) {
55645 - data_unset *dc = srv->config_context->data[0];
55647 - dc->print(dc, 0);
55648 - fprintf(stderr, "\n");
55650 - /* shouldn't happend */
55651 - fprintf(stderr, "global config not found\n");
55654 +int lighty_mainloop(server *srv) {
55655 + fdevent_revents *revents = fdevent_revents_init();
55657 - if (test_config) {
55658 - printf("Syntax OK\n");
55661 + while (!srv_shutdown) {
55666 - if (test_config || print_config) {
55667 - server_free(srv);
55671 - /* close stdin and stdout, as they are not needed */
55672 - /* move stdin to /dev/null */
55673 - if (-1 != (fd = open("/dev/null", O_RDONLY))) {
55674 - close(STDIN_FILENO);
55675 - dup2(fd, STDIN_FILENO);
55679 - /* move stdout to /dev/null */
55680 - if (-1 != (fd = open("/dev/null", O_WRONLY))) {
55681 - close(STDOUT_FILENO);
55682 - dup2(fd, STDOUT_FILENO);
55686 - if (0 != config_set_defaults(srv)) {
55687 - log_error_write(srv, __FILE__, __LINE__, "s",
55688 - "setting default values failed");
55689 - server_free(srv);
55693 - /* UID handling */
55694 -#ifdef HAVE_GETUID
55695 - if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
55696 - /* we are setuid-root */
55698 - log_error_write(srv, __FILE__, __LINE__, "s",
55699 - "Are you nuts ? Don't apply a SUID bit to this binary");
55701 - server_free(srv);
55706 - /* check document-root */
55707 - if (srv->config_storage[0]->document_root->used <= 1) {
55708 - log_error_write(srv, __FILE__, __LINE__, "s",
55709 - "document-root is not set\n");
55711 - server_free(srv);
55716 - if (plugins_load(srv)) {
55717 - log_error_write(srv, __FILE__, __LINE__, "s",
55718 - "loading plugins finally failed");
55720 - plugins_free(srv);
55721 - server_free(srv);
55726 - /* open pid file BEFORE chroot */
55727 - if (srv->srvconf.pid_file->used) {
55728 - 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))) {
55730 - if (errno != EEXIST) {
55731 - log_error_write(srv, __FILE__, __LINE__, "sbs",
55732 - "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
55736 - if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
55737 - log_error_write(srv, __FILE__, __LINE__, "sbs",
55738 - "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
55739 + if (handle_sig_hup) {
55742 + /* reset notification */
55743 + handle_sig_hup = 0;
55748 + /* send the old process into a graceful-shutdown and start a
55749 + * new process right away
55752 + * - if webserver is running on port < 1024 (e.g. 80, 433)
55753 + * we don't have the permissions to bind to that port anymore
55757 + if (0 == (pid = fork())) {
55758 + execve(argv[0], argv, envp);
55761 + } else if (pid == -1) {
55766 + graceful_shutdown = 1; /* shutdown without killing running connections */
55767 + graceful_restart = 1; /* don't delete pid file */
55770 - if (!S_ISREG(st.st_mode)) {
55771 - log_error_write(srv, __FILE__, __LINE__, "sb",
55772 - "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
55775 + /* cycle logfiles */
55777 + switch(r = plugins_call_handle_sighup(srv)) {
55778 + case HANDLER_GO_ON:
55781 + log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
55785 - if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
55786 - log_error_write(srv, __FILE__, __LINE__, "sbs",
55787 - "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
55789 + if (-1 == log_error_cycle()) {
55790 + log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
55797 + if (handle_sig_alarm) {
55798 + /* a new second */
55801 + /* reset notification */
55802 + handle_sig_alarm = 0;
55805 + /* get current time */
55806 + min_ts = time(NULL);
55808 + if (min_ts != srv->cur_ts) {
55810 + connections *conns = srv->conns;
55813 + switch(r = plugins_call_handle_trigger(srv)) {
55814 + case HANDLER_GO_ON:
55816 + case HANDLER_ERROR:
55817 + log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
55820 + log_error_write(srv, __FILE__, __LINE__, "d", r);
55824 + /* trigger waitpid */
55825 + srv->cur_ts = min_ts;
55827 + /* cleanup stat-cache */
55828 + stat_cache_trigger_cleanup(srv);
55830 + * check all connections for timeouts
55833 + for (ndx = 0; ndx < conns->used; ndx++) {
55838 + con = conns->ptr[ndx];
55840 + switch (con->state) {
55841 + case CON_STATE_READ_REQUEST_HEADER:
55842 + case CON_STATE_READ_REQUEST_CONTENT:
55843 + if (con->recv->is_closed) break; /* everything is read, no need to fear a timeout */
55845 + if (con->request_count == 1) {
55846 + if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
55849 + log_error_write(srv, __FILE__, __LINE__, "sd",
55850 + "connection closed - read-timeout:", con->fd);
55852 + TRACE("%s", "(timeout)");
55853 + connection_set_state(srv, con, CON_STATE_ERROR);
55857 + if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
55860 + log_error_write(srv, __FILE__, __LINE__, "sd",
55861 + "connection closed - read-timeout:", con->fd);
55863 + TRACE("%s", "(timeout)");
55864 + connection_set_state(srv, con, CON_STATE_ERROR);
55869 + case CON_STATE_WRITE_RESPONSE_HEADER:
55870 + case CON_STATE_WRITE_RESPONSE_CONTENT:
55873 + if (con->write_request_ts != 0 &&
55874 + srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
55877 + log_error_write(srv, __FILE__, __LINE__, "sbsosds",
55878 + "NOTE: a request for",
55879 + con->request.uri,
55880 + "timed out after writing",
55881 + con->bytes_written,
55882 + "bytes. We waited",
55883 + (int)con->conf.max_write_idle,
55884 + "seconds. If this a problem increase server.max-write-idle");
55886 + TRACE("%s", "(timeout)");
55887 + connection_set_state(srv, con, CON_STATE_ERROR);
55892 + /* the other ones are uninteresting */
55895 + /* we don't like div by zero */
55896 + if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
55898 + if (con->traffic_limit_reached &&
55899 + (con->conf.kbytes_per_second == 0 ||
55900 + ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
55901 + /* enable connection again */
55902 + con->traffic_limit_reached = 0;
55908 + connection_state_machine(srv, con);
55910 + con->bytes_written_cur_second = 0;
55911 + *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
55915 + fprintf(stderr, "connection-state: ");
55919 + fprintf(stderr, "c[%d,%d]: %s ",
55922 + connection_get_state(con->state));
55926 + if (cs == 1) fprintf(stderr, "\n");
55930 + if (srv->sockets_disabled) {
55931 + /* our server sockets are disabled, why ? */
55933 + if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
55934 + (srv->conns->used < srv->max_conns * 0.9) &&
55935 + (0 == graceful_shutdown)) {
55938 + for (i = 0; i < srv->srv_sockets.used; i++) {
55939 + server_socket *srv_socket = srv->srv_sockets.ptr[i];
55940 + fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
55943 + log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
55945 + srv->sockets_disabled = 0;
55948 + if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
55949 + (srv->conns->used > srv->max_conns) || /* out of connections */
55950 + (graceful_shutdown)) { /* graceful_shutdown */
55953 + /* disable server-fds */
55955 + for (i = 0; i < srv->srv_sockets.used; i++) {
55956 + server_socket *srv_socket = srv->srv_sockets.ptr[i];
55957 + fdevent_event_del(srv->ev, srv_socket->sock);
55959 + if (graceful_shutdown) {
55960 + /* we don't want this socket anymore,
55962 + * closing it right away will make it possible for
55963 + * the next lighttpd to take over (graceful restart)
55966 + fdevent_unregister(srv->ev, srv_socket->sock);
55967 + closesocket(srv_socket->sock->fd);
55968 + srv_socket->sock->fd = -1;
55970 + /* network_close() will cleanup after us */
55974 + if (graceful_shutdown) {
55975 + log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
55976 + } else if (srv->conns->used > srv->max_conns) {
55977 + log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
55979 + log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
55982 + srv->sockets_disabled = 1;
55986 + if (graceful_shutdown && srv->conns->used == 0) {
55987 + /* we are in graceful shutdown phase and all connections are closed
55988 + * we are ready to terminate without harming anyone */
55989 + srv_shutdown = 1;
55992 + /* we still have some fds to share */
55993 + if (srv->want_fds) {
55994 + /* check the fdwaitqueue for waiting fds */
55995 + int free_fds = srv->max_fds - srv->cur_fds - 16;
55998 + for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
55999 + connection_state_machine(srv, con);
56005 + if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
56006 + /* n is the number of events */
56008 + fdevent_get_revents(srv->ev, n, revents);
56010 + /* handle client connections first
56012 + * this is a bit of a hack, but we have to make sure than we handle
56013 + * close-events before the connection is reused for a keep-alive
56016 + * this is mostly an issue for mod_proxy_core, but you never know
56020 + for (i = 0; i < revents->used; i++) {
56021 + fdevent_revent *revent = revents->ptr[i];
56024 + /* skip server-fds */
56025 + if (revent->handler == network_server_handle_fdevent) continue;
56027 + switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
56028 + case HANDLER_FINISHED:
56029 + case HANDLER_GO_ON:
56030 + case HANDLER_WAIT_FOR_EVENT:
56031 + case HANDLER_WAIT_FOR_FD:
56033 + case HANDLER_ERROR:
56034 + /* should never happen */
56038 + log_error_write(srv, __FILE__, __LINE__, "d", r);
56043 + for (i = 0; i < revents->used; i++) {
56044 + fdevent_revent *revent = revents->ptr[i];
56047 + /* server fds only */
56048 + if (revent->handler != network_server_handle_fdevent) continue;
56050 + switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
56051 + case HANDLER_FINISHED:
56052 + case HANDLER_GO_ON:
56053 + case HANDLER_WAIT_FOR_EVENT:
56054 + case HANDLER_WAIT_FOR_FD:
56056 + case HANDLER_ERROR:
56057 + /* should never happen */
56061 + log_error_write(srv, __FILE__, __LINE__, "d", r);
56066 + } else if (n < 0 && errno != EINTR) {
56067 + log_error_write(srv, __FILE__, __LINE__, "ss",
56068 + "fdevent_poll failed:",
56069 + strerror(errno));
56072 + for (ndx = 0; ndx < srv->joblist->used; ndx++) {
56073 + connection *con = srv->joblist->ptr[ndx];
56076 + connection_state_machine(srv, con);
56078 + switch(r = plugins_call_handle_joblist(srv, con)) {
56079 + case HANDLER_FINISHED:
56080 + case HANDLER_GO_ON:
56083 + log_error_write(srv, __FILE__, __LINE__, "d", r);
56087 + con->in_joblist = 0;
56090 + srv->joblist->used = 0;
56093 + fdevent_revents_free(revents);
56099 +int main (int argc, char **argv, char **envp) {
56100 + server *srv = NULL;
56101 + int print_config = 0;
56102 + int test_config = 0;
56105 + int num_childs = 0;
56106 + int pid_fd = -1, fd;
56109 + char *optarg = NULL;
56112 +#ifdef HAVE_SIGACTION
56113 + struct sigaction act;
56115 +#ifdef HAVE_GETRLIMIT
56116 + struct rlimit rlim;
56120 + struct itimerval interval;
56122 + interval.it_interval.tv_sec = 1;
56123 + interval.it_interval.tv_usec = 0;
56124 + interval.it_value.tv_sec = 1;
56125 + interval.it_value.tv_usec = 0;
56129 + status_counter_init();
56131 + /* for nice %b handling in strfime() */
56132 + setlocale(LC_TIME, "C");
56134 + if (NULL == (srv = server_init())) {
56135 + fprintf(stderr, "did this really happen?\n");
56139 + /* init structs done */
56141 + srv->srvconf.port = 0;
56142 +#ifdef HAVE_GETUID
56143 + i_am_root = (getuid() == 0);
56147 + srv->srvconf.dont_daemonize = 0;
56149 + while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
56153 + /* evil HACK for windows, optarg is not set */
56154 + optarg = argv[optind-1];
56156 + if (config_read(srv, optarg)) {
56157 + server_free(srv);
56163 + buffer_copy_string(srv->srvconf.modules_dir, optarg);
56165 + case 'p': print_config = 1; break;
56166 + case 't': test_config = 1; break;
56167 + case 'D': srv->srvconf.dont_daemonize = 1; break;
56168 + case 'v': show_version(); return 0;
56169 + case 'V': show_features(); return 0;
56170 + case 'h': show_help(); return 0;
56173 + server_free(srv);
56178 + if (!srv->config_storage) {
56179 + log_error_write(srv, __FILE__, __LINE__, "s",
56180 + "No configuration available. Try using -f option.");
56182 + server_free(srv);
56186 + if (print_config) {
56187 + data_unset *dc = srv->config_context->data[0];
56189 + dc->print(dc, 0);
56190 + fprintf(stderr, "\n");
56192 + /* shouldn't happend */
56193 + fprintf(stderr, "global config not found\n");
56197 + if (test_config) {
56198 + printf("Syntax OK\n");
56201 + if (test_config || print_config) {
56202 + server_free(srv);
56206 + /* close stdin and stdout, as they are not needed */
56207 + /* move stdin to /dev/null */
56208 + if (-1 != (fd = open("/dev/null", O_RDONLY))) {
56209 + close(STDIN_FILENO);
56210 + dup2(fd, STDIN_FILENO);
56214 + /* move stdout to /dev/null */
56215 + if (-1 != (fd = open("/dev/null", O_WRONLY))) {
56216 + close(STDOUT_FILENO);
56217 + dup2(fd, STDOUT_FILENO);
56221 + if (0 != config_set_defaults(srv)) {
56222 + log_error_write(srv, __FILE__, __LINE__, "s",
56223 + "setting default values failed");
56224 + server_free(srv);
56228 + /* UID handling */
56229 +#ifdef HAVE_GETUID
56230 + if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
56231 + /* we are setuid-root */
56233 + log_error_write(srv, __FILE__, __LINE__, "s",
56234 + "Are you nuts ? Don't apply a SUID bit to this binary");
56236 + server_free(srv);
56241 + /* check document-root */
56242 + if (srv->config_storage[0]->document_root->used <= 1) {
56243 + log_error_write(srv, __FILE__, __LINE__, "s",
56244 + "document-root is not set\n");
56246 + server_free(srv);
56251 + if (plugins_load(srv)) {
56252 + log_error_write(srv, __FILE__, __LINE__, "s",
56253 + "loading plugins finally failed");
56255 + plugins_free(srv);
56256 + server_free(srv);
56262 + /* open pid file BEFORE chroot */
56263 + if (srv->srvconf.pid_file->used) {
56264 + 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))) {
56266 + if (errno != EEXIST) {
56267 + log_error_write(srv, __FILE__, __LINE__, "sbs",
56268 + "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
56272 + if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
56273 + log_error_write(srv, __FILE__, __LINE__, "sbs",
56274 + "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
56277 + if (!S_ISREG(st.st_mode)) {
56278 + log_error_write(srv, __FILE__, __LINE__, "sb",
56279 + "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
56283 + if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
56284 + log_error_write(srv, __FILE__, __LINE__, "sbs",
56285 + "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
56291 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
56292 /* select limits itself
56294 * as it is a hard limit and will lead to a segfault we add some safety
56296 - srv->max_fds = FD_SETSIZE - 200;
56297 + fprintf(stderr, "%s.%d: max parallel connections: %d\r\n", __FILE__, __LINE__, FD_SETSIZE);
56298 + srv->max_fds = FD_SETSIZE - 4;
56300 srv->max_fds = 4096;
56302 @@ -636,7 +1010,7 @@
56303 #ifdef HAVE_VALGRIND_VALGRIND_H
56304 if (RUNNING_ON_VALGRIND) use_rlimit = 0;
56308 #ifdef HAVE_GETRLIMIT
56309 if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
56310 log_error_write(srv, __FILE__, __LINE__,
56311 @@ -644,13 +1018,13 @@
56317 if (use_rlimit && srv->srvconf.max_fds) {
56321 rlim.rlim_cur = srv->srvconf.max_fds;
56322 rlim.rlim_max = srv->srvconf.max_fds;
56325 if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
56326 log_error_write(srv, __FILE__, __LINE__,
56327 "ss", "couldn't set 'max filedescriptors'",
56328 @@ -659,7 +1033,7 @@
56332 - /* #372: solaris need some fds extra for devpoll */
56333 + /* #372: solaris need some fds extra for devpoll */
56334 if (rlim.rlim_cur > 10) rlim.rlim_cur -= 10;
56336 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
56337 @@ -677,33 +1051,33 @@
56338 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
56339 /* don't raise the limit above FD_SET_SIZE */
56340 if (srv->max_fds > FD_SETSIZE - 200) {
56341 - log_error_write(srv, __FILE__, __LINE__, "sd",
56342 + log_error_write(srv, __FILE__, __LINE__, "sd",
56343 "can't raise max filedescriptors above", FD_SETSIZE - 200,
56344 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
56352 /* set user and group */
56353 if (srv->srvconf.username->used) {
56354 if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) {
56355 - log_error_write(srv, __FILE__, __LINE__, "sb",
56356 + log_error_write(srv, __FILE__, __LINE__, "sb",
56357 "can't find username", srv->srvconf.username);
56362 if (pwd->pw_uid == 0) {
56363 log_error_write(srv, __FILE__, __LINE__, "s",
56364 "I will not set uid to 0\n");
56370 if (srv->srvconf.groupname->used) {
56371 if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) {
56372 - log_error_write(srv, __FILE__, __LINE__, "sb",
56373 + log_error_write(srv, __FILE__, __LINE__, "sb",
56374 "can't find groupname", srv->srvconf.groupname);
56377 @@ -713,15 +1087,15 @@
56383 /* we need root-perms for port < 1024 */
56384 if (0 != network_init(srv)) {
56391 -#ifdef HAVE_CHROOT
56392 +#ifdef HAVE_CHROOT
56393 if (srv->srvconf.changeroot->used) {
56396 @@ -761,7 +1135,7 @@
56399 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
56400 - srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
56401 + srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 4 ? rlim.rlim_cur : FD_SETSIZE - 4;
56403 srv->max_fds = rlim.rlim_cur;
56405 @@ -775,18 +1149,18 @@
56407 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
56408 /* don't raise the limit above FD_SET_SIZE */
56409 - if (srv->max_fds > FD_SETSIZE - 200) {
56410 - log_error_write(srv, __FILE__, __LINE__, "sd",
56411 - "can't raise max filedescriptors above", FD_SETSIZE - 200,
56412 + if (srv->max_fds > FD_SETSIZE - 4) {
56413 + log_error_write(srv, __FILE__, __LINE__, "sd",
56414 + "can't raise max filedescriptors above", FD_SETSIZE - 4,
56415 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
56421 if (0 != network_init(srv)) {
56429 @@ -802,25 +1176,27 @@
56430 /* or use the default */
56431 srv->max_conns = srv->max_fds;
56435 if (HANDLER_GO_ON != plugins_call_init(srv)) {
56436 log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down.");
56440 network_close(srv);
56449 /* network is up, let's deamonize ourself */
56450 if (srv->srvconf.dont_daemonize == 0) daemonize();
56454 srv->gid = getgid();
56455 srv->uid = getuid();
56459 /* write pid file */
56460 if (pid_fd != -1) {
56461 buffer_copy_long(srv->tmp_buf, getpid());
56462 @@ -829,17 +1205,17 @@
56468 if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) {
56469 log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down.");
56473 network_close(srv);
56481 /* dump unused config-keys */
56482 for (i = 0; i < srv->config_context->used; i++) {
56483 array *config = ((data_config *)srv->config_context->data[i])->value;
56484 @@ -847,43 +1223,49 @@
56486 for (j = 0; config && j < config->used; j++) {
56487 data_unset *du = config->data[j];
56490 /* all var.* is known as user defined variable */
56491 if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) {
56495 if (NULL == array_get_element(srv->config_touched, du->key->ptr)) {
56496 - log_error_write(srv, __FILE__, __LINE__, "sbs",
56497 + log_error_write(srv, __FILE__, __LINE__, "sbs",
56498 "WARNING: unknown config-key:",
56505 - if (srv->config_deprecated) {
56507 + if (srv->config_unsupported) {
56508 log_error_write(srv, __FILE__, __LINE__, "s",
56509 + "Configuration contains unsupported keys. Going down.");
56512 + if (srv->config_deprecated) {
56513 + log_error_write(srv, __FILE__, __LINE__, "s",
56514 "Configuration contains deprecated keys. Going down.");
56518 + if (srv->config_unsupported || srv->config_deprecated) {
56520 network_close(srv);
56527 - if (-1 == log_error_open(srv)) {
56528 - log_error_write(srv, __FILE__, __LINE__, "s",
56530 + if (-1 == log_error_open(srv->srvconf.errorlog_file, srv->srvconf.errorlog_use_syslog)) {
56531 + log_error_write(srv, __FILE__, __LINE__, "s",
56532 "opening errorlog failed, dying");
56536 network_close(srv);
56543 #ifdef HAVE_SIGACTION
56544 memset(&act, 0, sizeof(act));
56545 act.sa_handler = SIG_IGN;
56546 @@ -903,7 +1285,7 @@
56547 sigaction(SIGHUP, &act, NULL);
56548 sigaction(SIGALRM, &act, NULL);
56549 sigaction(SIGCHLD, &act, NULL);
56552 #elif defined(HAVE_SIGNAL)
56553 /* ignore the SIGPIPE from sendfile() */
56554 signal(SIGPIPE, SIG_IGN);
56555 @@ -914,20 +1296,20 @@
56556 signal(SIGCHLD, signal_handler);
56557 signal(SIGINT, signal_handler);
56562 signal(SIGALRM, signal_handler);
56565 /* setup periodic timer (1 second) */
56566 if (setitimer(ITIMER_REAL, &interval, NULL)) {
56567 log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed");
56572 getitimer(ITIMER_REAL, &interval);
56577 /* start watcher and workers */
56578 num_childs = srv->srvconf.max_worker;
56579 if (num_childs > 0) {
56580 @@ -957,13 +1339,13 @@
56584 - if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) {
56585 + if (NULL == (srv->ev = fdevent_init(/*srv->max_fds + 1*/ 4096, srv->event_handler))) {
56586 log_error_write(srv, __FILE__, __LINE__,
56587 "s", "fdevent_init failed");
56591 - * kqueue() is called here, select resets its internals,
56593 + * kqueue() is called here, select resets its internals,
56594 * all server sockets get their handlers
56597 @@ -971,7 +1353,7 @@
56599 network_close(srv);
56606 @@ -986,17 +1368,17 @@
56608 if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
56609 if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) {
56610 - log_error_write(srv, __FILE__, __LINE__, "s",
56611 + log_error_write(srv, __FILE__, __LINE__, "s",
56612 "could not open a fam connection, dieing.");
56615 #ifdef HAVE_FAMNOEXISTS
56616 FAMNoExists(srv->stat_cache->fam);
56618 + srv->stat_cache->sock->fd = FAMCONNECTION_GETFD(srv->stat_cache->fam);
56620 - srv->stat_cache->fam_fcce_ndx = -1;
56621 - fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL);
56622 - fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN);
56623 + fdevent_register(srv->ev, srv->stat_cache->sock, stat_cache_handle_fdevent, NULL);
56624 + fdevent_event_add(srv->ev, srv->stat_cache->sock, FDEVENT_IN);
56628 @@ -1007,330 +1389,36 @@
56630 for (i = 0; i < srv->srv_sockets.used; i++) {
56631 server_socket *srv_socket = srv->srv_sockets.ptr[i];
56632 - if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) {
56633 + if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->sock)) {
56634 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno));
56640 - while (!srv_shutdown) {
56645 - if (handle_sig_hup) {
56648 - /* reset notification */
56649 - handle_sig_hup = 0;
56652 - /* cycle logfiles */
56654 - switch(r = plugins_call_handle_sighup(srv)) {
56655 - case HANDLER_GO_ON:
56658 - log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
56662 - if (-1 == log_error_cycle(srv)) {
56663 - log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
56669 - if (handle_sig_alarm) {
56670 - /* a new second */
56673 - /* reset notification */
56674 - handle_sig_alarm = 0;
56677 - /* get current time */
56678 - min_ts = time(NULL);
56680 - if (min_ts != srv->cur_ts) {
56682 - connections *conns = srv->conns;
56685 - switch(r = plugins_call_handle_trigger(srv)) {
56686 - case HANDLER_GO_ON:
56688 - case HANDLER_ERROR:
56689 - log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
56692 - log_error_write(srv, __FILE__, __LINE__, "d", r);
56696 - /* trigger waitpid */
56697 - srv->cur_ts = min_ts;
56699 - /* cleanup stat-cache */
56700 - stat_cache_trigger_cleanup(srv);
56702 - * check all connections for timeouts
56705 - for (ndx = 0; ndx < conns->used; ndx++) {
56710 - con = conns->ptr[ndx];
56712 - if (con->state == CON_STATE_READ ||
56713 - con->state == CON_STATE_READ_POST) {
56714 - if (con->request_count == 1) {
56715 - if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
56718 - log_error_write(srv, __FILE__, __LINE__, "sd",
56719 - "connection closed - read-timeout:", con->fd);
56721 - connection_set_state(srv, con, CON_STATE_ERROR);
56725 - if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
56728 - log_error_write(srv, __FILE__, __LINE__, "sd",
56729 - "connection closed - read-timeout:", con->fd);
56731 - connection_set_state(srv, con, CON_STATE_ERROR);
56737 - if ((con->state == CON_STATE_WRITE) &&
56738 - (con->write_request_ts != 0)) {
56740 - if (srv->cur_ts - con->write_request_ts > 60) {
56741 - log_error_write(srv, __FILE__, __LINE__, "sdd",
56742 - "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
56746 - if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
56749 - log_error_write(srv, __FILE__, __LINE__, "sbsosds",
56750 - "NOTE: a request for",
56751 - con->request.uri,
56752 - "timed out after writing",
56753 - con->bytes_written,
56754 - "bytes. We waited",
56755 - (int)con->conf.max_write_idle,
56756 - "seconds. If this a problem increase server.max-write-idle");
56758 - connection_set_state(srv, con, CON_STATE_ERROR);
56762 - /* we don't like div by zero */
56763 - if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
56765 - if (con->traffic_limit_reached &&
56766 - (con->conf.kbytes_per_second == 0 ||
56767 - ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
56768 - /* enable connection again */
56769 - con->traffic_limit_reached = 0;
56775 - connection_state_machine(srv, con);
56777 - con->bytes_written_cur_second = 0;
56778 - *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
56782 - fprintf(stderr, "connection-state: ");
56786 - fprintf(stderr, "c[%d,%d]: %s ",
56789 - connection_get_state(con->state));
56793 - if (cs == 1) fprintf(stderr, "\n");
56797 - if (srv->sockets_disabled) {
56798 - /* our server sockets are disabled, why ? */
56800 - if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
56801 - (srv->conns->used < srv->max_conns * 0.9) &&
56802 - (0 == graceful_shutdown)) {
56803 - for (i = 0; i < srv->srv_sockets.used; i++) {
56804 - server_socket *srv_socket = srv->srv_sockets.ptr[i];
56805 - fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
56808 - log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
56810 - srv->sockets_disabled = 0;
56813 - if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
56814 - (srv->conns->used > srv->max_conns) || /* out of connections */
56815 - (graceful_shutdown)) { /* graceful_shutdown */
56817 - /* disable server-fds */
56819 - for (i = 0; i < srv->srv_sockets.used; i++) {
56820 - server_socket *srv_socket = srv->srv_sockets.ptr[i];
56821 - fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
56823 - if (graceful_shutdown) {
56824 - /* we don't want this socket anymore,
56826 - * closing it right away will make it possible for
56827 - * the next lighttpd to take over (graceful restart)
56830 - fdevent_unregister(srv->ev, srv_socket->fd);
56831 - close(srv_socket->fd);
56832 - srv_socket->fd = -1;
56834 - /* network_close() will cleanup after us */
56838 - if (graceful_shutdown) {
56839 - log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
56840 - } else if (srv->conns->used > srv->max_conns) {
56841 - log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
56843 - log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
56846 - srv->sockets_disabled = 1;
56849 + lighty_mainloop(srv);
56851 - if (graceful_shutdown && srv->conns->used == 0) {
56852 - /* we are in graceful shutdown phase and all connections are closed
56853 - * we are ready to terminate without harming anyone */
56854 - srv_shutdown = 1;
56857 - /* we still have some fds to share */
56858 - if (srv->want_fds) {
56859 - /* check the fdwaitqueue for waiting fds */
56860 - int free_fds = srv->max_fds - srv->cur_fds - 16;
56863 - for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
56864 - connection_state_machine(srv, con);
56869 + status_counter_free();
56871 - if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
56872 - /* n is the number of events */
56877 - log_error_write(srv, __FILE__, __LINE__, "sd",
56883 - fdevent_handler handler;
56887 - fd_ndx = fdevent_event_next_fdndx (srv->ev, fd_ndx);
56888 - revents = fdevent_event_get_revent (srv->ev, fd_ndx);
56889 - fd = fdevent_event_get_fd (srv->ev, fd_ndx);
56890 - handler = fdevent_get_handler(srv->ev, fd);
56891 - context = fdevent_get_context(srv->ev, fd);
56893 - /* connection_handle_fdevent needs a joblist_append */
56895 - log_error_write(srv, __FILE__, __LINE__, "sdd",
56896 - "event for", fd, revents);
56898 - switch (r = (*handler)(srv, context, revents)) {
56899 - case HANDLER_FINISHED:
56900 - case HANDLER_GO_ON:
56901 - case HANDLER_WAIT_FOR_EVENT:
56902 - case HANDLER_WAIT_FOR_FD:
56904 - case HANDLER_ERROR:
56905 - /* should never happen */
56909 - log_error_write(srv, __FILE__, __LINE__, "d", r);
56912 - } while (--n > 0);
56913 - } else if (n < 0 && errno != EINTR) {
56914 - log_error_write(srv, __FILE__, __LINE__, "ss",
56915 - "fdevent_poll failed:",
56916 - strerror(errno));
56919 - for (ndx = 0; ndx < srv->joblist->used; ndx++) {
56920 - connection *con = srv->joblist->ptr[ndx];
56923 - connection_state_machine(srv, con);
56925 - switch(r = plugins_call_handle_joblist(srv, con)) {
56926 - case HANDLER_FINISHED:
56927 - case HANDLER_GO_ON:
56930 - log_error_write(srv, __FILE__, __LINE__, "d", r);
56934 - con->in_joblist = 0;
56937 - srv->joblist->used = 0;
56940 - if (srv->srvconf.pid_file->used &&
56941 + if (0 == graceful_restart &&
56942 + srv->srvconf.pid_file->used &&
56943 srv->srvconf.changeroot->used == 0) {
56944 if (0 != unlink(srv->srvconf.pid_file->ptr)) {
56945 if (errno != EACCES && errno != EPERM) {
56946 - log_error_write(srv, __FILE__, __LINE__, "sbds",
56947 - "unlink failed for:",
56948 + log_error_write(srv, __FILE__, __LINE__, "sbds",
56949 + "unlink failed for:",
56950 srv->srvconf.pid_file,
56959 - log_error_close(srv);
56960 network_close(srv);
56961 connections_free(srv);
56969 --- ../lighttpd-1.4.11/src/settings.h 2005-08-11 01:26:41.000000000 +0300
56970 +++ lighttpd-1.5.0/src/settings.h 2006-07-16 00:26:04.000000000 +0300
56973 * max size of a buffer which will just be reset
56974 * to ->used = 0 instead of really freeing the buffer
56977 * 64kB (no real reason, just a guess)
56979 #define BUFFER_MAX_REUSE_SIZE (4 * 1024)
56982 * max size of the HTTP request header
56985 * 32k should be enough for everything (just a guess)
56989 #define MAX_HTTP_REQUEST_HEADER (32 * 1024)
56991 -typedef enum { HANDLER_UNSET,
56993 +typedef enum { HANDLER_UNSET,
56996 - HANDLER_COMEBACK,
56997 - HANDLER_WAIT_FOR_EVENT,
56998 + HANDLER_COMEBACK,
56999 + HANDLER_WAIT_FOR_EVENT,
57001 HANDLER_WAIT_FOR_FD
57003 --- ../lighttpd-1.4.11/src/spawn-fcgi.c 2006-03-07 14:18:10.000000000 +0200
57004 +++ lighttpd-1.5.0/src/spawn-fcgi.c 2006-07-16 00:26:04.000000000 +0300
57006 #include <sys/types.h>
57007 -#include <sys/time.h>
57008 #include <sys/stat.h>
57010 #include <stdlib.h>
57011 #include <string.h>
57014 -#include <unistd.h>
57018 #ifdef HAVE_CONFIG_H
57019 #include "config.h"
57029 #include "sys-socket.h"
57030 +#include "sys-files.h"
57032 #ifdef HAVE_SYS_WAIT_H
57033 #include <sys/wait.h>
57034 @@ -45,28 +43,28 @@
57036 int socket_type, status;
57037 struct timeval tv = { 0, 100 * 1000 };
57040 struct sockaddr_un fcgi_addr_un;
57041 struct sockaddr_in fcgi_addr_in;
57042 struct sockaddr *fcgi_addr;
57048 if (child_count < 2) {
57053 if (child_count > 256) {
57061 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
57064 fcgi_addr_un.sun_family = AF_UNIX;
57065 strcpy(fcgi_addr_un.sun_path, unixsocket);
57069 servlen = SUN_LEN(&fcgi_addr_un);
57071 @@ -84,50 +82,50 @@
57073 fcgi_addr_in.sin_port = htons(port);
57074 servlen = sizeof(fcgi_addr_in);
57077 socket_type = AF_INET;
57078 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
57082 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
57083 - fprintf(stderr, "%s.%d\n",
57084 + fprintf(stderr, "%s.%d\n",
57085 __FILE__, __LINE__);
57090 if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
57091 /* server is not up, spawn in */
57096 if (unixsocket) unlink(unixsocket);
57102 /* reopen socket */
57103 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
57104 - fprintf(stderr, "%s.%d\n",
57105 + fprintf(stderr, "%s.%d\n",
57106 __FILE__, __LINE__);
57111 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
57112 - fprintf(stderr, "%s.%d\n",
57113 + fprintf(stderr, "%s.%d\n",
57114 __FILE__, __LINE__);
57118 /* create socket */
57119 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
57120 - fprintf(stderr, "%s.%d: bind failed: %s\n",
57121 + fprintf(stderr, "%s.%d: bind failed: %s\n",
57122 __FILE__, __LINE__,
57128 if (-1 == listen(fcgi_fd, 1024)) {
57129 - fprintf(stderr, "%s.%d: fd = -1\n",
57130 + fprintf(stderr, "%s.%d: fd = -1\n",
57131 __FILE__, __LINE__);
57134 @@ -137,42 +135,45 @@
57142 char cgi_childs[64];
57149 + /* loose control terminal */
57152 /* is save as we limit to 256 childs */
57153 sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count);
57156 if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
57157 close(FCGI_LISTENSOCK_FILENO);
57158 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
57163 /* we don't need the client socket */
57164 for (i = 3; i < 256; i++) {
57169 /* create environment */
57172 putenv(cgi_childs);
57175 /* fork and replace shell */
57176 b = malloc(strlen("exec ") + strlen(appPath) + 1);
57177 strcpy(b, "exec ");
57178 strcat(b, appPath);
57182 execl("/bin/sh", "sh", "-c", b, NULL);
57191 @@ -180,47 +181,47 @@
57198 select(0, NULL, NULL, NULL, &tv);
57201 switch (waitpid(child, &status, WNOHANG)) {
57203 - fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
57204 + fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
57205 __FILE__, __LINE__,
57209 /* write pid file */
57210 if (pid_fd != -1) {
57211 /* assume a 32bit pid_t */
57215 snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child);
57218 write(pid_fd, pidbuf, strlen(pidbuf));
57228 if (WIFEXITED(status)) {
57229 - fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
57230 + fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
57231 __FILE__, __LINE__,
57232 WEXITSTATUS(status), strerror(WEXITSTATUS(status)));
57233 } else if (WIFSIGNALED(status)) {
57234 - fprintf(stderr, "%s.%d: child signaled: %d\n",
57235 + fprintf(stderr, "%s.%d: child signaled: %d\n",
57236 __FILE__, __LINE__,
57239 - fprintf(stderr, "%s.%d: child died somehow: %d\n",
57240 + fprintf(stderr, "%s.%d: child died somehow: %d\n",
57241 __FILE__, __LINE__,
57250 @@ -228,16 +229,16 @@
57251 __FILE__, __LINE__);
57263 void show_version () {
57264 char *b = "spawn-fcgi" "-" PACKAGE_VERSION \
57265 -" - spawns fastcgi processes\n"
57266 +" - spawns fastcgi processes\n"
57268 write(1, b, strlen(b));
57270 @@ -265,7 +266,7 @@
57273 int main(int argc, char **argv) {
57274 - char *fcgi_app = NULL, *changeroot = NULL, *username = NULL,
57275 + char *fcgi_app = NULL, *changeroot = NULL, *username = NULL,
57276 *groupname = NULL, *unixsocket = NULL, *pid_file = NULL,
57278 unsigned short port = 0;
57279 @@ -273,9 +274,9 @@
57285 i_am_root = (getuid() == 0);
57288 while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) {
57290 case 'f': fcgi_app = optarg; break;
57291 @@ -290,137 +291,137 @@
57292 case 'P': pid_file = optarg; /* PID file */ break;
57293 case 'v': show_version(); return 0;
57294 case 'h': show_help(); return 0;
57303 if (fcgi_app == NULL || (port == 0 && unixsocket == NULL)) {
57309 if (unixsocket && port) {
57310 - fprintf(stderr, "%s.%d: %s\n",
57311 + fprintf(stderr, "%s.%d: %s\n",
57312 __FILE__, __LINE__,
57313 "either a unix domain socket or a tcp-port, but not both\n");
57320 if (unixsocket && strlen(unixsocket) > UNIX_PATH_MAX - 1) {
57321 - fprintf(stderr, "%s.%d: %s\n",
57322 + fprintf(stderr, "%s.%d: %s\n",
57323 __FILE__, __LINE__,
57324 "path of the unix socket is too long\n");
57331 if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
57332 /* we are setuid-root */
57334 - fprintf(stderr, "%s.%d: %s\n",
57336 + fprintf(stderr, "%s.%d: %s\n",
57337 __FILE__, __LINE__,
57338 "Are you nuts ? Don't apply a SUID bit to this binary\n");
57347 (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)))) {
57349 if (errno != EEXIST) {
57350 - fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
57351 + fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
57352 __FILE__, __LINE__,
57353 pid_file, strerror(errno));
57360 /* ok, file exists */
57363 if (0 != stat(pid_file, &st)) {
57364 - fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n",
57365 + fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n",
57366 __FILE__, __LINE__,
57367 pid_file, strerror(errno));
57374 /* is it a regular file ? */
57377 if (!S_ISREG(st.st_mode)) {
57378 - fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n",
57379 + fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n",
57380 __FILE__, __LINE__,
57388 if (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
57389 - fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
57390 + fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
57391 __FILE__, __LINE__,
57392 pid_file, strerror(errno));
57401 struct group *grp = NULL;
57402 struct passwd *pwd = NULL;
57405 /* set user and group */
57409 if (NULL == (pwd = getpwnam(username))) {
57410 - fprintf(stderr, "%s.%d: %s, %s\n",
57411 + fprintf(stderr, "%s.%d: %s, %s\n",
57412 __FILE__, __LINE__,
57413 "can't find username", username);
57418 if (pwd->pw_uid == 0) {
57419 - fprintf(stderr, "%s.%d: %s\n",
57420 + fprintf(stderr, "%s.%d: %s\n",
57421 __FILE__, __LINE__,
57422 "I will not set uid to 0\n");
57429 if (NULL == (grp = getgrnam(groupname))) {
57430 - fprintf(stderr, "%s.%d: %s %s\n",
57431 + fprintf(stderr, "%s.%d: %s %s\n",
57432 __FILE__, __LINE__,
57433 - "can't find groupname",
57434 + "can't find groupname",
57438 if (grp->gr_gid == 0) {
57439 - fprintf(stderr, "%s.%d: %s\n",
57440 + fprintf(stderr, "%s.%d: %s\n",
57441 __FILE__, __LINE__,
57442 "I will not set gid to 0\n");
57449 if (-1 == chroot(changeroot)) {
57450 - fprintf(stderr, "%s.%d: %s %s\n",
57451 + fprintf(stderr, "%s.%d: %s %s\n",
57452 __FILE__, __LINE__,
57453 "chroot failed: ", strerror(errno));
57456 if (-1 == chdir("/")) {
57457 - fprintf(stderr, "%s.%d: %s %s\n",
57458 + fprintf(stderr, "%s.%d: %s %s\n",
57459 __FILE__, __LINE__,
57460 "chdir failed: ", strerror(errno));
57466 /* drop root privs */
57468 setgid(grp->gr_gid);
57469 @@ -428,7 +429,7 @@
57471 if (username) setuid(pwd->pw_uid);
57475 return fcgi_spawn_connection(fcgi_app, addr, port, unixsocket, child_count, pid_fd, nofork);
57478 --- ../lighttpd-1.4.11/src/splaytree.c 2005-09-12 21:51:28.000000000 +0300
57479 +++ lighttpd-1.5.0/src/splaytree.c 2006-07-16 00:26:03.000000000 +0300
57480 @@ -56,19 +56,19 @@
57482 #define node_size splaytree_size
57484 -/* Splay using the key i (which may or may not be in the tree.)
57485 - * The starting root is t, and the tree used is defined by rat
57486 +/* Splay using the key i (which may or may not be in the tree.)
57487 + * The starting root is t, and the tree used is defined by rat
57488 * size fields are maintained */
57489 splay_tree * splaytree_splay (splay_tree *t, int i) {
57490 splay_tree N, *l, *r, *y;
57491 int comp, root_size, l_size, r_size;
57494 if (t == NULL) return t;
57495 N.left = N.right = NULL;
57497 root_size = node_size(t);
57498 l_size = r_size = 0;
57502 comp = compare(i, t->key);
57504 @@ -120,7 +120,7 @@
57506 r_size -= 1+node_size(y->right);
57510 l->right = t->left; /* assemble */
57511 r->left = t->right;
57513 --- ../lighttpd-1.4.11/src/splaytree.h 2005-09-12 21:51:13.000000000 +0300
57514 +++ lighttpd-1.5.0/src/splaytree.h 2006-07-16 00:26:03.000000000 +0300
57516 /* This macro returns the size of a node. Unlike "x->size", */
57517 /* it works even if x=NULL. The test could be avoided by using */
57518 /* a special version of NULL which was a real node with size 0. */
57523 --- ../lighttpd-1.4.11/src/stat_cache.c 2005-11-22 15:23:51.000000000 +0200
57524 +++ lighttpd-1.5.0/src/stat_cache.c 2006-09-07 00:57:05.000000000 +0300
57526 #include <stdlib.h>
57527 #include <string.h>
57529 -#include <unistd.h>
57532 #include <assert.h>
57536 #include "sys-mmap.h"
57538 -/* NetBSD 1.3.x needs it */
57539 -#ifndef MAP_FAILED
57540 -# define MAP_FAILED -1
57543 -#ifndef O_LARGEFILE
57544 -# define O_LARGEFILE 0
57547 -#ifndef HAVE_LSTAT
57548 -#define lstat stat
57550 +#include "sys-files.h"
57551 +#include "sys-strings.h"
57554 /* enables debug code for testing if all nodes in the stat-cache as accessable */
57557 * if we get a change-event from FAM, we increment the version in the FAM->dir mapping
57559 - * if the stat()-cache is queried we check if the version id for the directory is the
57560 - * same and return immediatly.
57561 + * if the stat()-cache is queried we check if the version id for the directory is the
57562 + * same and return immediatly.
57566 @@ -62,17 +50,17 @@
57567 * - for each FAMRequest we have to find the version in the directory cache (index as userdata)
57569 * stat <<-> directory <-> FAMRequest
57571 - * if file is deleted, directory is dirty, file is rechecked ...
57573 + * if file is deleted, directory is dirty, file is rechecked ...
57574 * if directory is deleted, directory mapping is removed
57588 @@ -83,16 +71,16 @@
57590 * - the hash-key is used as sorting criteria for a tree
57591 * - a splay-tree is used as we can use the caching effect of it
57595 /* we want to cleanup the stat-cache every few seconds, let's say 10
57597 * - remove entries which are outdated since 30s
57598 * - remove entries which are fresh but havn't been used since 60s
57599 * - if we don't have a stat-cache entry for a directory, release it from the monitor
57603 -#ifdef DEBUG_STAT_CACHE
57604 +#ifdef DEBUG_STAT_CACHE
57608 @@ -105,15 +93,16 @@
57610 stat_cache *stat_cache_init(void) {
57611 stat_cache *fc = NULL;
57614 fc = calloc(1, sizeof(*fc));
57617 fc->dir_name = buffer_init();
57619 fc->fam = calloc(1, sizeof(*fc->fam));
57620 + fc->sock = iosocket_init();
57623 -#ifdef DEBUG_STAT_CACHE
57624 +#ifdef DEBUG_STAT_CACHE
57628 @@ -122,24 +111,24 @@
57630 static stat_cache_entry * stat_cache_entry_init(void) {
57631 stat_cache_entry *sce = NULL;
57634 sce = calloc(1, sizeof(*sce));
57637 sce->name = buffer_init();
57638 sce->etag = buffer_init();
57639 sce->content_type = buffer_init();
57645 static void stat_cache_entry_free(void *data) {
57646 stat_cache_entry *sce = data;
57650 buffer_free(sce->etag);
57651 buffer_free(sce->name);
57652 buffer_free(sce->content_type);
57658 @@ -148,22 +137,22 @@
57659 fam_dir_entry *fam_dir = NULL;
57661 fam_dir = calloc(1, sizeof(*fam_dir));
57664 fam_dir->name = buffer_init();
57670 static void fam_dir_entry_free(void *data) {
57671 fam_dir_entry *fam_dir = data;
57674 if (!fam_dir) return;
57677 FAMCancelMonitor(fam_dir->fc, fam_dir->req);
57680 buffer_free(fam_dir->name);
57681 free(fam_dir->req);
57687 @@ -174,7 +163,7 @@
57688 splay_tree *node = sc->files;
57690 osize = sc->files->size;
57693 stat_cache_entry_free(node->data);
57694 sc->files = splaytree_delete(sc->files, node->key);
57696 @@ -187,12 +176,12 @@
57699 splay_tree *node = sc->dirs;
57702 osize = sc->dirs->size;
57704 fam_dir_entry_free(node->data);
57705 sc->dirs = splaytree_delete(sc->dirs, node->key);
57709 assert(NULL == sc->dirs);
57711 @@ -202,6 +191,7 @@
57715 + iosocket_free(sc->sock);
57719 @@ -212,7 +202,7 @@
57720 static int stat_cache_attr_get(buffer *buf, char *name) {
57726 buffer_prepare_copy(buf, attrlen);
57728 @@ -251,15 +241,15 @@
57731 events = FAMPending(sc->fam);
57734 for (i = 0; i < events; i++) {
57736 fam_dir_entry *fam_dir;
57741 FAMNextEvent(sc->fam, &fe);
57747 @@ -280,7 +270,7 @@
57749 sc->dirs = splaytree_splay(sc->dirs, ndx);
57753 if (node && (node->key == ndx)) {
57754 int osize = splaytree_size(sc->dirs);
57756 @@ -298,17 +288,15 @@
57758 if (revent & FDEVENT_HUP) {
57759 /* fam closed the connection */
57760 - srv->stat_cache->fam_fcce_ndx = -1;
57762 - fdevent_event_del(srv->ev, &(sc->fam_fcce_ndx), FAMCONNECTION_GETFD(sc->fam));
57763 - fdevent_unregister(srv->ev, FAMCONNECTION_GETFD(sc->fam));
57764 + fdevent_event_del(srv->ev, sc->sock);
57765 + fdevent_unregister(srv->ev, sc->sock);
57774 return HANDLER_GO_ON;
57777 @@ -328,11 +316,25 @@
57782 +static int stat_cache_lstat(server *srv, char *dname, struct stat *lst) {
57783 + if (lstat(dname, lst) == 0) {
57784 + return S_ISLNK(lst->st_mode) ? 0 : 1;
57787 + log_error_write(srv, __FILE__, __LINE__, "sss",
57788 + "lstat failed for:",
57789 + dname, strerror(errno));
57801 * - HANDLER_FINISHED on cache-miss (don't forget to reopen the file)
57802 * - HANDLER_ERROR on stat() failed -> see errno for problem
57804 @@ -348,16 +350,16 @@
57808 -#ifdef DEBUG_STAT_CACHE
57809 +#ifdef DEBUG_STAT_CACHE
57814 splay_tree *file_node = NULL;
57821 * check if the directory for this file has changed
57824 @@ -366,23 +368,23 @@
57825 file_ndx = hashme(name);
57826 sc->files = splaytree_splay(sc->files, file_ndx);
57828 -#ifdef DEBUG_STAT_CACHE
57829 +#ifdef DEBUG_STAT_CACHE
57830 for (i = 0; i < ctrl.used; i++) {
57831 if (ctrl.ptr[i] == file_ndx) break;
57835 if (sc->files && (sc->files->key == file_ndx)) {
57836 -#ifdef DEBUG_STAT_CACHE
57837 +#ifdef DEBUG_STAT_CACHE
57838 /* it was in the cache */
57839 assert(i < ctrl.used);
57842 - /* we have seen this file already and
57844 + /* we have seen this file already and
57845 * don't stat() it again in the same second */
57847 file_node = sc->files;
57850 sce = file_node->data;
57852 /* check if the name is the same, we might have a collision */
57853 @@ -390,7 +392,7 @@
57854 if (buffer_is_equal(name, sce->name)) {
57855 if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) {
57856 if (sce->stat_ts == srv->cur_ts) {
57859 return HANDLER_GO_ON;
57862 @@ -400,15 +402,15 @@
57863 * file_node is used by the FAM check below to see if we know this file
57864 * and if we can save a stat().
57866 - * BUT, the sce is not reset here as the entry into the cache is ok, we
57867 + * BUT, the sce is not reset here as the entry into the cache is ok, we
57868 * it is just not pointing to our requested file.
57876 -#ifdef DEBUG_STAT_CACHE
57877 +#ifdef DEBUG_STAT_CACHE
57878 if (i != ctrl.used) {
57879 fprintf(stderr, "%s.%d: %08x was already inserted but not found in cache, %s\n", __FILE__, __LINE__, file_ndx, name->ptr);
57881 @@ -424,23 +426,23 @@
57884 dir_ndx = hashme(sc->dir_name);
57887 sc->dirs = splaytree_splay(sc->dirs, dir_ndx);
57890 if (sc->dirs && (sc->dirs->key == dir_ndx)) {
57891 dir_node = sc->dirs;
57895 if (dir_node && file_node) {
57896 /* we found a file */
57899 sce = file_node->data;
57900 fam_dir = dir_node->data;
57903 if (fam_dir->version == sce->dir_version) {
57904 /* the stat()-cache entry is still ok */
57909 return HANDLER_GO_ON;
57912 @@ -448,12 +450,11 @@
57918 * - open() + fstat() on a named-pipe results in a (intended) hang.
57919 - * - stat() if regualar file + open() to see if we can read from it is better
57920 + * - stat() if regular file + open() to see if we can read from it is better
57924 if (-1 == stat(name->ptr, &st)) {
57925 return HANDLER_ERROR;
57927 @@ -469,16 +470,16 @@
57934 osize = sc->files->size;
57937 sce = stat_cache_entry_init();
57938 buffer_copy_string_buffer(sce->name, name);
57940 - sc->files = splaytree_insert(sc->files, file_ndx, sce);
57941 -#ifdef DEBUG_STAT_CACHE
57943 + sc->files = splaytree_insert(sc->files, file_ndx, sce);
57944 +#ifdef DEBUG_STAT_CACHE
57945 if (ctrl.size == 0) {
57948 @@ -499,29 +500,70 @@
57950 sce->stat_ts = srv->cur_ts;
57952 - /* catch the obvious symlinks
57953 + /* catch the obvious symlinks
57955 * this is not a secure check as we still have a race-condition between
57956 - * the stat() and the open. We can only solve this by
57957 + * the stat() and the open. We can only solve this by
57958 * 1. open() the file
57959 * 2. fstat() the fd
57961 * and keeping the file open for the rest of the time. But this can
57962 * only be done at network level.
57965 - if (S_ISLNK(st.st_mode) && !con->conf.follow_symlink) {
57966 - return HANDLER_ERROR;
57969 + * per default it is not a symlink
57972 + sce->is_symlink = 0;
57974 + if (stat_cache_lstat(srv, name->ptr, &lst) == 0) {
57975 +#ifdef DEBUG_STAT_CACHE
57976 + log_error_write(srv, __FILE__, __LINE__, "sb",
57977 + "found symlink", name);
57979 + sce->is_symlink = 1;
57982 - if (S_ISREG(st.st_mode)) {
57984 + * we assume "/" can not be symlink, so
57985 + * skip the symlink stuff if our path is /
57987 + else if ((name->used > 2)) {
57988 + char *dname, *s_cur;
57990 + dname = strndup(name->ptr, name->used);
57991 + while ((s_cur = strrchr(dname,'/'))) {
57993 + if (dname == s_cur) {
57994 +#ifdef DEBUG_STAT_CACHE
57995 + log_error_write(srv, __FILE__, __LINE__, "s", "reached /");
57999 +#ifdef DEBUG_STAT_CACHE
58000 + log_error_write(srv, __FILE__, __LINE__, "sss",
58001 + "checking if", dname, "is a symlink");
58003 + if (stat_cache_lstat(srv, dname, &lst) == 0) {
58004 + sce->is_symlink = 1;
58005 +#ifdef DEBUG_STAT_CACHE
58006 + log_error_write(srv, __FILE__, __LINE__, "ss",
58007 + "found symlink", dname);
58016 + if (S_ISREG(st.st_mode)) {
58017 /* determine mimetype */
58018 buffer_reset(sce->content_type);
58021 for (k = 0; k < con->conf.mimetypes->used; k++) {
58022 data_string *ds = (data_string *)con->conf.mimetypes->data[k];
58023 buffer *type = ds->key;
58026 if (type->used == 0) continue;
58028 /* check if the right side is the same */
58029 @@ -538,8 +580,10 @@
58030 stat_cache_attr_get(sce->content_type, name->ptr);
58033 + } else if (S_ISDIR(st.st_mode)) {
58034 + etag_create(sce->etag, &(sce->st));
58040 (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM)) {
58041 @@ -549,19 +593,19 @@
58042 fam_dir->fc = sc->fam;
58044 buffer_copy_string_buffer(fam_dir->name, sc->dir_name);
58047 fam_dir->version = 1;
58050 fam_dir->req = calloc(1, sizeof(FAMRequest));
58052 - if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr,
58054 + if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr,
58055 fam_dir->req, fam_dir)) {
58057 - log_error_write(srv, __FILE__, __LINE__, "sbs",
58058 - "monitoring dir failed:",
58061 + log_error_write(srv, __FILE__, __LINE__, "sbs",
58062 + "monitoring dir failed:",
58064 FamErrlist[FAMErrno]);
58067 fam_dir_entry_free(fam_dir);
58070 @@ -570,7 +614,7 @@
58071 osize = sc->dirs->size;
58074 - sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir);
58075 + sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir);
58077 assert(sc->dirs->data == fam_dir);
58078 assert(osize == (sc->dirs->size - 1));
58079 @@ -578,9 +622,9 @@
58081 fam_dir = dir_node->data;
58085 /* bind the fam_fc to the stat() cache entry */
58089 sce->dir_version = fam_dir->version;
58090 sce->dir_ndx = dir_ndx;
58091 @@ -594,11 +638,11 @@
58095 - * remove stat() from cache which havn't been stat()ed for
58096 + * remove stat() from cache which havn't been stat()ed for
58097 * more than 10 seconds
58100 - * walk though the stat-cache, collect the ids which are too old
58102 + * walk though the stat-cache, collect the ids which are too old
58103 * and remove them in a second loop
58106 @@ -639,9 +683,9 @@
58107 sc->files = splaytree_splay(sc->files, ndx);
58112 if (node && (node->key == ndx)) {
58113 -#ifdef DEBUG_STAT_CACHE
58114 +#ifdef DEBUG_STAT_CACHE
58116 int osize = splaytree_size(sc->files);
58117 stat_cache_entry *sce = node->data;
58118 @@ -649,7 +693,7 @@
58119 stat_cache_entry_free(node->data);
58120 sc->files = splaytree_delete(sc->files, ndx);
58122 -#ifdef DEBUG_STAT_CACHE
58123 +#ifdef DEBUG_STAT_CACHE
58124 for (j = 0; j < ctrl.used; j++) {
58125 if (ctrl.ptr[j] == ndx) {
58126 ctrl.ptr[j] = ctrl.ptr[--ctrl.used];
58127 --- ../lighttpd-1.4.11/src/status_counter.c 1970-01-01 03:00:00.000000000 +0300
58128 +++ lighttpd-1.5.0/src/status_counter.c 2006-07-19 20:02:55.000000000 +0300
58130 +#include <stdlib.h>
58132 +#include "status_counter.h"
58134 + * The status array can carry all the status information you want
58135 + * the key to the array is <module-prefix>.<name>
58136 + * and the values are counters
58139 + * fastcgi.backends = 10
58140 + * fastcgi.active-backends = 6
58141 + * fastcgi.backend.<key>.load = 24
58142 + * fastcgi.backend.<key>....
58144 + * fastcgi.backend.<key>.disconnects = ...
58147 +static array *counters = NULL;
58149 +void status_counter_init(void) {
58150 + counters = array_init();
58152 +void status_counter_free(void) {
58153 + array_free(counters);
58156 +array *status_counter_get_array(void) {
58160 +data_integer *status_counter_get_counter(const char *s, size_t len) {
58161 + data_integer *di;
58162 + array *status = status_counter_get_array();
58164 + if (NULL == (di = (data_integer *)array_get_element(status, s))) {
58165 + /* not found, create it */
58167 + if (NULL == (di = (data_integer *)array_get_unused_element(status, TYPE_INTEGER))) {
58168 + di = data_integer_init();
58170 + buffer_copy_string_len(di->key, s, len);
58173 + array_insert_unique(status, (data_unset *)di);
58178 +/* dummies of the statistic framework functions
58179 + * they will be moved to a statistics.c later */
58180 +int status_counter_inc(const char *s, size_t len) {
58181 + data_integer *di = status_counter_get_counter(s, len);
58188 +int status_counter_dec(const char *s, size_t len) {
58189 + data_integer *di = status_counter_get_counter(s, len);
58191 + if (di->value > 0) di->value--;
58196 +int status_counter_set(const char *s, size_t len, int val) {
58197 + data_integer *di = status_counter_get_counter(s, len);
58205 --- ../lighttpd-1.4.11/src/status_counter.h 1970-01-01 03:00:00.000000000 +0300
58206 +++ lighttpd-1.5.0/src/status_counter.h 2006-07-19 20:02:55.000000000 +0300
58208 +#ifndef _STATUS_COUNTER_H_
58209 +#define _STATUS_COUNTER_H_
58211 +#include <sys/types.h>
58213 +#include "array.h"
58215 +void status_counter_init(void);
58216 +void status_counter_free(void);
58217 +array *status_counter_get_array(void);
58218 +data_integer *status_counter_get_counter(const char *s, size_t len);
58219 +int status_counter_inc(const char *s, size_t len);
58220 +int status_counter_dec(const char *s, size_t len);
58221 +int status_counter_set(const char *s, size_t len, int val);
58224 --- ../lighttpd-1.4.11/src/stream.c 2005-09-23 21:50:15.000000000 +0300
58225 +++ lighttpd-1.5.0/src/stream.c 2006-07-16 00:26:04.000000000 +0300
58227 #include <sys/types.h>
58228 #include <sys/stat.h>
58230 -#include <unistd.h>
58233 #include "stream.h"
58237 #include "sys-mmap.h"
58238 +#include "sys-files.h"
58241 # define O_BINARY 0
58242 @@ -19,39 +19,39 @@
58246 -#elif defined __WIN32
58247 +#elif defined _WIN32
58255 if (-1 == stat(fn->ptr, &st)) {
58260 f->size = st.st_size;
58263 if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY))) {
58268 f->start = mmap(0, f->size, PROT_READ, MAP_SHARED, fd, 0);
58274 if (MAP_FAILED == f->start) {
58278 -#elif defined __WIN32
58279 - fh = CreateFile(fn->ptr,
58284 - FILE_ATTRIBUTE_READONLY,
58285 +#elif defined _WIN32
58286 + fh = CreateFile(fn->ptr,
58291 + FILE_ATTRIBUTE_READONLY,
58294 if (!fh) return -1;
58299 - FORMAT_MESSAGE_ALLOCATE_BUFFER |
58300 + FORMAT_MESSAGE_ALLOCATE_BUFFER |
58301 FORMAT_MESSAGE_FROM_SYSTEM,
58310 p = MapViewOfFile(mh,
58317 -# error no mmap found
58318 +# error no mmap found
58325 --- ../lighttpd-1.4.11/src/sys-files.h 1970-01-01 03:00:00.000000000 +0300
58326 +++ lighttpd-1.5.0/src/sys-files.h 2006-07-16 00:26:04.000000000 +0300
58328 +#ifndef _SYS_FILES_H_
58329 +#define _SYS_FILES_H_
58331 +#define DIR_SEPERATOR_UNIX '/'
58332 +#define DIR_SEPERATOR_WIN '\\'
58335 +#include <windows.h>
58336 +#include <io.h> /* open */
58337 +#include <direct.h> /* chdir */
58339 +#include "buffer.h"
58341 +#define DIR_SEPERATOR DIR_SEPERATOR_WIN
58343 +#define __S_ISTYPE(mode, mask) (((mode) & _S_IFMT) == (mask))
58345 +#define S_ISDIR(mode) __S_ISTYPE((mode), _S_IFDIR)
58346 +#define S_ISCHR(mode) __S_ISTYPE((mode), _S_IFCHR)
58347 +#define S_ISBLK(mode) __S_ISTYPE((mode), _S_IFBLK)
58348 +#define S_ISREG(mode) __S_ISTYPE((mode), _S_IFREG)
58349 +/* we don't support symlinks */
58350 +#define S_ISLNK(mode) 0
58352 +#define lstat stat
58353 +#define mkstemp mktemp
58354 +#define mkdir(x, y) mkdir(x)
58357 + const char *d_name;
58362 + WIN32_FIND_DATA finddata;
58363 + struct dirent dent;
58366 +DIR *opendir(const char *dn);
58367 +struct dirent *readdir(DIR *d);
58368 +void closedir(DIR *d);
58370 +buffer *filename_unix2local(buffer *b);
58371 +buffer *pathname_unix2local(buffer *b);
58374 +#include <unistd.h>
58375 +#include <dirent.h>
58377 +#define DIR_SEPERATOR DIR_SEPERATOR_UNIX
58379 +#define filename_unix2local(x) (x)
58380 +#define pathname_unix2local(x) (x)
58383 +#define PATHNAME_APPEND_SLASH(x) \
58384 + if (x->used > 1 && x->ptr[x->used - 2] != DIR_SEPERATOR) { \
58385 + char sl[2] = { DIR_SEPERATOR, 0 }; \
58386 + BUFFER_APPEND_STRING_CONST(x, sl); \
58389 +#ifndef O_LARGEFILE
58390 +# define O_LARGEFILE 0
58395 --- ../lighttpd-1.4.11/src/sys-mmap.h 2005-08-11 01:26:34.000000000 +0300
58396 +++ lighttpd-1.5.0/src/sys-mmap.h 2006-07-16 00:26:04.000000000 +0300
58398 #ifndef WIN32_MMAP_H
58399 #define WIN32_MMAP_H
58404 #define MAP_FAILED -1
58405 #define PROT_SHARED 0
58406 --- ../lighttpd-1.4.11/src/sys-process.h 1970-01-01 03:00:00.000000000 +0300
58407 +++ lighttpd-1.5.0/src/sys-process.h 2006-07-16 00:26:04.000000000 +0300
58409 +#ifndef _SYS_PROCESS_H_
58410 +#define _SYS_PROCESS_H_
58413 +#include <process.h>
58415 +/* win32 has no fork() */
58416 +#define kill(x, y)
58417 +#define getpid() 0
58420 +#include <sys/wait.h>
58421 +#include <unistd.h>
58426 --- ../lighttpd-1.4.11/src/sys-socket.h 2005-08-11 01:26:39.000000000 +0300
58427 +++ lighttpd-1.5.0/src/sys-socket.h 2006-09-07 00:57:05.000000000 +0300
58429 #ifndef WIN32_SOCKET_H
58430 #define WIN32_SOCKET_H
58433 +#ifdef HAVE_CONFIG_H
58434 +#include "config.h"
58439 #include <winsock2.h>
58441 #define ECONNRESET WSAECONNRESET
58442 #define EINPROGRESS WSAEINPROGRESS
58443 #define EALREADY WSAEALREADY
58444 +#define ENOTCONN WSAENOTCONN
58445 +#define EWOULDBLOCK WSAEWOULDBLOCK
58446 #define ioctl ioctlsocket
58447 #define hstrerror(x) ""
58448 +#define STDIN_FILENO 0
58449 +#define STDOUT_FILENO 1
58450 +#define STDERR_FILENO 2
58451 +#define ssize_t int
58453 +int inet_aton(const char *cp, struct in_addr *inp);
58454 +#define HAVE_INET_ADDR
58455 +#undef HAVE_INET_ATON
58458 +#include <sys/types.h> /* required by netinet/tcp.h on FreeBSD */
58459 #include <sys/socket.h>
58460 #include <sys/ioctl.h>
58461 #include <netinet/in.h>
58463 #include <sys/un.h>
58464 #include <arpa/inet.h>
58467 +#define SUN_LEN(su) \
58468 + (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
58471 +#define closesocket(x) close(x)
58474 +#endif /* !_WIN32 */
58476 +#ifdef HAVE_INET_NTOP
58477 +/* only define it if it isn't defined yet */
58485 + struct sockaddr_in6 ipv6;
58487 + struct sockaddr_in ipv4;
58488 +#ifdef HAVE_SYS_UN_H
58489 + struct sockaddr_un un;
58491 + struct sockaddr plain;
58495 --- ../lighttpd-1.4.11/src/sys-strings.h 1970-01-01 03:00:00.000000000 +0300
58496 +++ lighttpd-1.5.0/src/sys-strings.h 2006-07-16 00:26:03.000000000 +0300
58498 +#ifndef _SYS_STRINGS_H_
58499 +#define _SYS_STRINGS_H_
58502 +#define strcasecmp stricmp
58503 +#define strncasecmp strnicmp
58504 +#define strtoll(p, e, b) _strtoi64(p, e, b)
58509 --- ../lighttpd-1.4.11/tests/LightyTest.pm 2006-01-14 20:32:31.000000000 +0200
58510 +++ lighttpd-1.5.0/tests/LightyTest.pm 2006-09-07 00:57:05.000000000 +0300
58511 @@ -87,14 +87,16 @@
58512 # pre-process configfile if necessary
58515 - unlink($self->{TESTDIR}."/tmp/cfg.file");
58516 - system("cat ".$self->{SRCDIR}."/".$self->{CONFIGFILE}.' | perl -pe "s#\@SRCDIR\@#'.$self->{BASEDIR}.'/tests/#" > '.$self->{TESTDIR}.'/tmp/cfg.file');
58517 + $ENV{'SRCDIR'} = $self->{BASEDIR}.'/tests';
58518 + $ENV{'PORT'} = $self->{PORT};
58520 unlink($self->{LIGHTTPD_PIDFILE});
58522 - system($self->{LIGHTTPD_PATH}." -f ".$self->{TESTDIR}."/tmp/cfg.file -m ".$self->{MODULES_PATH});
58523 + if (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'strace') {
58524 + system("strace -tt -s 512 -o strace ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &");
58525 + } elsif (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'valgrind') {
58526 + system("valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --log-file=valgrind ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &");
58528 - 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}." &");
58529 + system($self->{LIGHTTPD_PATH}." -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH});
58532 select(undef, undef, undef, 0.1);
58533 @@ -184,7 +186,7 @@
58534 (my $h = $1) =~ tr/[A-Z]/[a-z]/;
58536 if (defined $resp_hdr{$h}) {
58537 - diag(sprintf("header %s is duplicated: %s and %s\n",
58538 + diag(sprintf("header '%s' is duplicated: '%s' and '%s'\n",
58539 $h, $resp_hdr{$h}, $2));
58541 $resp_hdr{$h} = $2;
58542 @@ -196,6 +198,9 @@
58546 + $t->{etag} = $resp_hdr{'etag'};
58547 + $t->{date} = $resp_hdr{'date'};
58550 if (defined $resp_hdr{"content-length"}) {
58551 $resp_body = substr($lines, 0, $resp_hdr{"content-length"});
58552 --- ../lighttpd-1.4.11/tests/Makefile.am 2005-09-16 15:48:40.000000000 +0300
58553 +++ lighttpd-1.5.0/tests/Makefile.am 2006-07-16 00:26:05.000000000 +0300
58554 @@ -39,10 +39,18 @@
58569 + proxy-backend-1.conf \
58570 + proxy-backend-2.conf
58573 TESTS_ENVIRONMENT=$(srcdir)/wrapper.sh $(srcdir) $(top_builddir)
58574 --- ../lighttpd-1.4.11/tests/bug-06.conf 2005-08-27 17:44:19.000000000 +0300
58575 +++ lighttpd-1.5.0/tests/bug-06.conf 2006-07-16 00:26:04.000000000 +0300
58577 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58578 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
58579 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58580 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
58582 ## bind to port (default: 80)
58586 ## bind to localhost (default: all interfaces)
58587 server.bind = "localhost"
58588 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
58589 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
58590 server.name = "www.example.org"
58591 server.tag = "Apache 1.3.29"
58594 ######################## MODULE CONFIG ############################
58597 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
58598 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
58600 mimetype.assign = ( ".png" => "image/png",
58601 ".jpg" => "image/jpeg",
58603 ".c" => "text/plain",
58604 ".conf" => "text/plain" )
58606 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
58607 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
58608 compress.filetype = ("text/plain", "text/html")
58610 setenv.add-environment = ( "TRAC_ENV" => "foo")
58612 "host" => "127.0.0.1",
58614 # "mode" => "authorizer",
58615 -# "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
58616 +# "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
58620 @@ -106,7 +106,7 @@
58621 ssl.pemfile = "server.pem"
58623 auth.backend = "plain"
58624 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
58625 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
58626 auth.backend.plain.groupfile = "lighttpd.group"
58628 auth.backend.ldap.hostname = "localhost"
58629 @@ -149,15 +149,15 @@
58630 status.config-url = "/server-config"
58632 simple-vhost.document-root = "pages"
58633 -simple-vhost.server-root = "@SRCDIR@/tmp/lighttpd/servers/"
58634 +simple-vhost.server-root = env.SRCDIR + "/tmp/lighttpd/servers/"
58635 simple-vhost.default-host = "www.example.org"
58637 $HTTP["host"] == "vvv.example.org" {
58638 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58639 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58642 $HTTP["host"] == "zzz.example.org" {
58643 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58644 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58645 server.name = "zzz.example.org"
58648 --- ../lighttpd-1.4.11/tests/bug-12.conf 2005-08-27 17:44:19.000000000 +0300
58649 +++ lighttpd-1.5.0/tests/bug-12.conf 2006-07-16 00:26:04.000000000 +0300
58651 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58652 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
58653 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58654 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
58656 ## bind to port (default: 80)
58660 ## bind to localhost (default: all interfaces)
58661 server.bind = "localhost"
58662 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
58663 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
58664 server.name = "www.example.org"
58665 server.tag = "Apache 1.3.29"
58668 ######################## MODULE CONFIG ############################
58671 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
58672 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
58674 mimetype.assign = ( ".png" => "image/png",
58675 ".jpg" => "image/jpeg",
58677 ".c" => "text/plain",
58678 ".conf" => "text/plain" )
58680 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
58681 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
58682 compress.filetype = ("text/plain", "text/html")
58684 setenv.add-environment = ( "TRAC_ENV" => "foo")
58686 "host" => "127.0.0.1",
58688 # "mode" => "authorizer",
58689 -# "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
58690 +# "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
58694 @@ -108,7 +108,7 @@
58695 ssl.pemfile = "server.pem"
58697 auth.backend = "plain"
58698 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
58699 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
58700 auth.backend.plain.groupfile = "lighttpd.group"
58702 auth.backend.ldap.hostname = "localhost"
58703 @@ -151,15 +151,15 @@
58704 status.config-url = "/server-config"
58706 simple-vhost.document-root = "pages"
58707 -simple-vhost.server-root = "@SRCDIR@/tmp/lighttpd/servers/"
58708 +simple-vhost.server-root = env.SRCDIR + "/tmp/lighttpd/servers/"
58709 simple-vhost.default-host = "www.example.org"
58711 $HTTP["host"] == "vvv.example.org" {
58712 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58713 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58716 $HTTP["host"] == "zzz.example.org" {
58717 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58718 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58719 server.name = "zzz.example.org"
58722 --- ../lighttpd-1.4.11/tests/cachable.t 1970-01-01 03:00:00.000000000 +0300
58723 +++ lighttpd-1.5.0/tests/cachable.t 2006-07-18 13:03:40.000000000 +0300
58725 +#!/usr/bin/env perl
58727 + # add current source dir to the include-path
58728 + # we need this for make distcheck
58729 + (my $srcdir = $0) =~ s#/[^/]+$#/#;
58730 + unshift @INC, $srcdir;
58735 +use Test::More tests => 12;
58738 +my $tf = LightyTest->new();
58741 +$tf->{CONFIGFILE} = 'lighttpd.conf';
58743 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
58745 +## check if If-Modified-Since, If-None-Match works
58747 +$t->{REQUEST} = ( <<EOF
58749 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT
58752 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
58753 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since');
58755 +$t->{REQUEST} = ( <<EOF
58757 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
58760 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Last-Modified' => ''} ];
58761 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since, comment');
58763 +my $now = $t->{date};
58765 +$t->{REQUEST} = ( <<EOF
58767 +If-Modified-Since: $now
58770 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
58771 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since');
58773 +$t->{REQUEST} = ( <<EOF
58775 +If-Modified-Since: $now; foo
58778 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
58779 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since, comment');
58781 +$t->{REQUEST} = ( <<EOF
58783 +If-None-Match: foo
58786 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+ETag' => ''} ];
58787 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
58789 +my $etag = $t->{etag};
58791 +$t->{REQUEST} = ( <<EOF
58793 +If-None-Match: $etag
58796 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
58797 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
58799 +$t->{REQUEST} = ( <<EOF
58801 +If-None-Match: $etag
58802 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
58805 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
58806 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + old Last-Modified');
58808 +$t->{REQUEST} = ( <<EOF
58810 +If-None-Match: $etag
58811 +If-Modified-Since: $now; foo
58814 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
58815 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag, Last-Modified + comment');
58817 +$t->{REQUEST} = ( <<EOF
58819 +If-None-Match: Foo
58820 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
58823 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
58824 +ok($tf->handle_http($t) == 0, 'Conditional GET - old ETAG + old Last-Modified');
58826 +$t->{REQUEST} = ( <<EOF
58828 +If-None-Match: $etag
58829 +If-Modified-Since: $now foo
58832 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 412 } ];
58833 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + Last-Modified + overlong timestamp');
58835 +ok($tf->stop_proc == 0, "Stopping lighttpd");
58837 --- ../lighttpd-1.4.11/tests/condition.conf 2005-08-27 17:44:19.000000000 +0300
58838 +++ lighttpd-1.5.0/tests/condition.conf 2006-07-16 00:26:05.000000000 +0300
58840 debug.log-request-handling = "enable"
58841 debug.log-condition-handling = "enable"
58843 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58844 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
58845 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58846 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
58848 ## bind to port (default: 80)
58851 ## bind to localhost (default: all interfaces)
58852 server.bind = "localhost"
58853 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
58854 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
58855 server.name = "www.example.org"
58856 server.tag = "Apache 1.3.29"
58858 @@ -22,25 +22,25 @@
58859 ######################## MODULE CONFIG ############################
58862 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
58863 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
58865 mimetype.assign = ( ".html" => "text/html" )
58867 url.redirect = ("^" => "/default")
58869 $HTTP["host"] == "www.example.org" {
58870 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58871 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58872 server.name = "www.example.org"
58873 url.redirect = ("^" => "/match_1")
58875 else $HTTP["host"] == "test1.example.org" {
58876 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58877 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58878 server.name = "test1.example.org"
58879 url.redirect = ("^" => "/match_2")
58882 else $HTTP["host"] == "test2.example.org" {
58883 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58884 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58885 server.name = "test2.example.org"
58886 url.redirect = ("^" => "/match_3")
58891 else $HTTP["host"] == "test3.example.org" {
58892 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58893 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58894 server.name = "test3.example.org"
58895 url.redirect = ("^" => "/match_4")
58897 --- ../lighttpd-1.4.11/tests/core-keepalive.t 2005-11-17 15:54:19.000000000 +0200
58898 +++ lighttpd-1.5.0/tests/core-keepalive.t 2006-07-16 00:26:05.000000000 +0300
58901 GET /12345.txt HTTP/1.0
58902 Host: 123.example.org
58903 -Connection: keep-alive
58907 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } , { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
58908 --- ../lighttpd-1.4.11/tests/core.t 2006-03-04 19:08:22.000000000 +0200
58909 +++ lighttpd-1.5.0/tests/core.t 2006-09-07 00:57:05.000000000 +0300
58910 @@ -44,21 +44,21 @@
58914 -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
58915 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 505 } ];
58916 ok($tf->handle_http($t) == 0, 'missing major version');
58918 $t->{REQUEST} = ( <<EOF
58922 -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
58923 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 505 } ];
58924 ok($tf->handle_http($t) == 0, 'missing minor version');
58926 $t->{REQUEST} = ( <<EOF
58930 -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
58931 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 505 } ];
58932 ok($tf->handle_http($t) == 0, 'strings as version');
58934 $t->{REQUEST} = ( <<EOF
58935 --- ../lighttpd-1.4.11/tests/default.conf 1970-01-01 03:00:00.000000000 +0300
58936 +++ lighttpd-1.5.0/tests/default.conf 2006-07-16 00:26:05.000000000 +0300
58938 +server.name = "www.example.org"
58940 +## bind to port (default: 80)
58941 +server.port = env.PORT
58944 +server.dir-listing = "enable"
58946 +#server.event-handler = "linux-sysepoll"
58947 +#server.event-handler = "linux-rtsig"
58949 +server.modules = (
58956 + "mod_simple_vhost",
58958 + "mod_secdownload",
58965 + "mod_accesslog" )
58967 +server.indexfiles = ( "index.php", "index.html",
58968 + "index.htm", "default.htm" )
58970 +ssi.extension = ( ".shtml" )
58972 +######################## MODULE CONFIG ############################
58975 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
58976 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
58978 +mimetype.assign = ( ".png" => "image/png",
58979 + ".jpg" => "image/jpeg",
58980 + ".jpeg" => "image/jpeg",
58981 + ".gif" => "image/gif",
58982 + ".html" => "text/html",
58983 + ".htm" => "text/html",
58984 + ".pdf" => "application/pdf",
58985 + ".swf" => "application/x-shockwave-flash",
58986 + ".spl" => "application/futuresplash",
58987 + ".txt" => "text/plain",
58988 + ".tar.gz" => "application/x-tgz",
58989 + ".tgz" => "application/x-tgz",
58990 + ".gz" => "application/x-gzip",
58991 + ".c" => "text/plain",
58992 + ".conf" => "text/plain" )
58994 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
58995 +compress.filetype = ("text/plain", "text/html")
58997 +setenv.add-environment = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
58999 +cgi.assign = ( ".pl" => "/usr/bin/perl",
59000 + ".cgi" => "/usr/bin/perl",
59001 + ".py" => "/usr/bin/python" )
59003 +userdir.include-user = ( "jan" )
59004 +userdir.path = "/"
59006 +ssl.engine = "disable"
59007 +ssl.pemfile = "server.pem"
59009 +auth.backend = "plain"
59010 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
59011 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
59012 +auth.backend.plain.groupfile = "lighttpd.group"
59014 +auth.backend.ldap.hostname = "localhost"
59015 +auth.backend.ldap.base-dn = "dc=my-domain,dc=com"
59016 +auth.backend.ldap.filter = "(uid=$)"
59018 +auth.require = ( "/server-status" =>
59020 + "method" => "digest",
59021 + "realm" => "download archiv",
59022 + "require" => "valid-user"
59026 + "method" => "basic",
59027 + "realm" => "download archiv",
59028 + "require" => "user=jan"
59030 + "/server-config" =>
59032 + "method" => "basic",
59033 + "realm" => "download archiv",
59034 + "require" => "valid-user"
59038 +url.access-deny = ( "~", ".inc")
59040 +url.redirect = ( "^/redirect/$" => "http://localhost:2048/" )
59042 +url.rewrite = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
59043 + "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
59045 +#### status module
59046 +status.status-url = "/server-status"
59047 +status.config-url = "/server-config"
59049 --- ../lighttpd-1.4.11/tests/docroot/www/dummydir/.svn/entries 2006-03-09 19:21:49.000000000 +0200
59050 +++ lighttpd-1.5.0/tests/docroot/www/dummydir/.svn/entries 2006-09-07 00:57:05.000000000 +0300
59054 uuid="152afb58-edef-0310-8abb-c4023f1b3aa9"
59055 - revision="1040"/>
59056 + repos="svn://svn.lighttpd.net/lighttpd"
59057 + revision="1277"/>
59059 --- ../lighttpd-1.4.11/tests/fastcgi-10.conf 2005-08-31 23:36:34.000000000 +0300
59060 +++ lighttpd-1.5.0/tests/fastcgi-10.conf 2006-07-16 00:26:04.000000000 +0300
59062 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59063 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
59064 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59065 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
59067 ## bind to port (default: 80)
59070 ## bind to localhost (default: all interfaces)
59071 server.bind = "localhost"
59072 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
59073 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
59074 server.name = "www.example.org"
59075 server.tag = "Apache 1.3.29"
59078 ######################## MODULE CONFIG ############################
59081 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
59082 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
59084 mimetype.assign = ( ".png" => "image/png",
59085 ".jpg" => "image/jpeg",
59087 ".c" => "text/plain",
59088 ".conf" => "text/plain" )
59090 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
59091 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
59092 compress.filetype = ("text/plain", "text/html")
59096 ssl.pemfile = "server.pem"
59098 auth.backend = "plain"
59099 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
59100 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
59101 auth.backend.plain.groupfile = "lighttpd.group"
59103 auth.backend.ldap.hostname = "localhost"
59104 @@ -128,11 +128,11 @@
59105 status.config-url = "/server-config"
59107 $HTTP["host"] == "vvv.example.org" {
59108 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59109 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59112 $HTTP["host"] == "zzz.example.org" {
59113 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59114 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59115 server.name = "zzz.example.org"
59118 --- ../lighttpd-1.4.11/tests/fastcgi-13.conf 2006-01-03 12:38:17.000000000 +0200
59119 +++ lighttpd-1.5.0/tests/fastcgi-13.conf 2006-07-18 13:03:40.000000000 +0300
59121 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59122 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
59123 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59124 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
59126 debug.log-request-header = "enable"
59127 debug.log-response-header = "enable"
59130 ## bind to localhost (default: all interfaces)
59131 server.bind = "localhost"
59132 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
59133 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
59134 server.name = "www.example.org"
59135 server.tag = "Apache 1.3.29"
59138 ######################## MODULE CONFIG ############################
59141 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
59142 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
59144 mimetype.assign = ( ".png" => "image/png",
59145 ".jpg" => "image/jpeg",
59147 ".c" => "text/plain",
59148 ".conf" => "text/plain" )
59150 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
59151 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
59152 compress.filetype = ("text/plain", "text/html")
59157 "host" => "127.0.0.1",
59159 - "bin-path" => "/home/jan/Documents/php-5.1.0/sapi/cgi/php -c /usr/local/lib/php.ini",
59160 + "bin-path" => "/home/jan/Documents/php-5.1.4/sapi/cgi/php -c /usr/local/lib/php.ini",
59161 "bin-copy-environment" => ( "PATH", "SHELL", "USER" ),
59164 @@ -102,7 +102,7 @@
59165 ssl.pemfile = "server.pem"
59167 auth.backend = "plain"
59168 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
59169 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
59170 auth.backend.plain.groupfile = "lighttpd.group"
59172 auth.backend.ldap.hostname = "localhost"
59173 @@ -145,11 +145,11 @@
59174 status.config-url = "/server-config"
59176 $HTTP["host"] == "vvv.example.org" {
59177 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59178 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59181 $HTTP["host"] == "zzz.example.org" {
59182 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59183 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59184 server.name = "zzz.example.org"
59187 --- ../lighttpd-1.4.11/tests/fastcgi-auth.conf 2005-08-27 17:44:19.000000000 +0300
59188 +++ lighttpd-1.5.0/tests/fastcgi-auth.conf 2006-07-16 00:26:05.000000000 +0300
59190 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59191 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
59192 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59193 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
59195 debug.log-request-header = "enable"
59196 debug.log-response-header = "enable"
59199 ## bind to localhost (default: all interfaces)
59200 server.bind = "localhost"
59201 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
59202 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
59203 server.name = "www.example.org"
59204 server.tag = "Apache 1.3.29"
59207 ######################## MODULE CONFIG ############################
59210 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
59211 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
59213 mimetype.assign = ( ".png" => "image/png",
59214 ".jpg" => "image/jpeg",
59216 ".c" => "text/plain",
59217 ".conf" => "text/plain" )
59219 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
59220 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
59221 compress.filetype = ("text/plain", "text/html")
59226 "host" => "127.0.0.1",
59228 - "bin-path" => "@SRCDIR@/fcgi-auth",
59229 + "bin-path" => env.SRCDIR + "/fcgi-auth",
59230 "mode" => "authorizer",
59231 - "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
59232 + "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
59236 @@ -106,7 +106,7 @@
59237 ssl.pemfile = "server.pem"
59239 auth.backend = "plain"
59240 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
59241 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
59242 auth.backend.plain.groupfile = "lighttpd.group"
59244 auth.backend.ldap.hostname = "localhost"
59245 @@ -149,11 +149,11 @@
59246 status.config-url = "/server-config"
59248 $HTTP["host"] == "vvv.example.org" {
59249 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59250 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59253 $HTTP["host"] == "zzz.example.org" {
59254 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59255 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59256 server.name = "zzz.example.org"
59259 --- ../lighttpd-1.4.11/tests/fastcgi-responder.conf 2005-08-27 17:44:19.000000000 +0300
59260 +++ lighttpd-1.5.0/tests/fastcgi-responder.conf 2006-07-16 00:26:05.000000000 +0300
59262 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59263 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
59264 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59265 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
59267 #debug.log-request-header = "enable"
59268 #debug.log-response-header = "enable"
59271 ## bind to localhost (default: all interfaces)
59272 server.bind = "localhost"
59273 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
59274 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
59275 server.name = "www.example.org"
59276 server.tag = "Apache 1.3.29"
59279 ######################## MODULE CONFIG ############################
59282 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
59283 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
59285 mimetype.assign = ( ".png" => "image/png",
59286 ".jpg" => "image/jpeg",
59288 ".c" => "text/plain",
59289 ".conf" => "text/plain" )
59291 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
59292 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
59293 compress.filetype = ("text/plain", "text/html")
59296 @@ -90,10 +90,11 @@
59298 "host" => "127.0.0.1",
59300 - "bin-path" => "@SRCDIR@/fcgi-responder",
59301 + "bin-path" => env.SRCDIR + "/fcgi-responder",
59302 "check-local" => "disable",
59305 + "min-procs" => 1,
59306 + "allow-x-send-file" => "enable",
59310 @@ -109,7 +110,7 @@
59311 ssl.pemfile = "server.pem"
59313 auth.backend = "plain"
59314 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
59315 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
59316 auth.backend.plain.groupfile = "lighttpd.group"
59318 auth.backend.ldap.hostname = "localhost"
59319 @@ -152,11 +153,11 @@
59320 status.config-url = "/server-config"
59322 $HTTP["host"] == "vvv.example.org" {
59323 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59324 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59327 $HTTP["host"] == "zzz.example.org" {
59328 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59329 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59330 server.name = "zzz.example.org"
59333 --- ../lighttpd-1.4.11/tests/fcgi-responder.c 2005-08-11 01:26:55.000000000 +0300
59334 +++ lighttpd-1.5.0/tests/fcgi-responder.c 2006-07-16 00:26:05.000000000 +0300
59337 int num_requests = 2;
59339 - while (num_requests > 0 &&
59340 - FCGI_Accept() >= 0) {
59343 - if (NULL != (p = getenv("QUERY_STRING"))) {
59344 + while (num_requests > 0 && FCGI_Accept() >= 0) {
59346 + char* doc_root = NULL;
59347 + char fname[4096];
59348 + char* pfname = (char *)fname;
59350 + doc_root = getenv("DOCUMENT_ROOT");
59351 + p = getenv("QUERY_STRING");
59353 + if (NULL != p && NULL != doc_root) {
59354 + snprintf(pfname, sizeof(fname), "%s/phpinfo.php", doc_root);
59355 if (0 == strcmp(p, "lf")) {
59356 printf("Status: 200 OK\n\n");
59357 } else if (0 == strcmp(p, "crlf")) {
59359 printf("Status: 200 OK\r\n");
59362 + } else if (0 == strcmp(p,"x-lighttpd-send-file")) {
59363 + printf("Status: 200 OK\r\n");
59364 + printf("X-LIGHTTPD-send-file: %s\r\n", pfname);
59366 + } else if (0 == strcmp(p,"xsendfile")) {
59367 + printf("Status: 200 OK\r\n");
59368 + printf("X-Sendfile: %s\r\n", pfname);
59370 + } else if (0 == strcmp(p,"xsendfile-mixed-case")) {
59371 + printf("Status: 200 OK\r\n");
59372 + printf("X-SeNdFiLe: %s\r\n", pfname);
59374 } else if (0 == strcmp(p, "die-at-end")) {
59375 printf("Status: 200 OK\r\n\r\n");
59377 --- ../lighttpd-1.4.11/tests/lighttpd.conf 2006-03-09 15:26:58.000000000 +0200
59378 +++ lighttpd-1.5.0/tests/lighttpd.conf 2006-09-07 00:57:05.000000000 +0300
59380 -debug.log-request-handling = "enable"
59381 -debug.log-condition-handling = "enable"
59382 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59383 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
59384 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59385 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
59386 +server.tag = "Apache 1.3.29"
59388 +debug.log-request-handling = "enable"
59389 +debug.log-response-header = "enable"
59390 ## 64 Mbyte ... nice limit
59391 server.max-request-size = 65000
59393 -## bind to port (default: 80)
59394 -server.port = 2048
59395 +include "default.conf"
59397 -## bind to localhost (default: all interfaces)
59398 -server.bind = "localhost"
59399 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
59400 -server.name = "www.example.org"
59401 -server.tag = "Apache 1.3.29"
59403 -server.dir-listing = "enable"
59405 -#server.event-handler = "linux-sysepoll"
59406 -#server.event-handler = "linux-rtsig"
59408 -#server.modules.path = ""
59409 -server.modules = (
59412 - "mod_secdownload",
59418 - "mod_simple_vhost",
59421 -# "mod_localizer",
59427 - "mod_accesslog" )
59429 -server.indexfiles = ( "index.php", "index.html",
59430 - "index.htm", "default.htm" )
59433 -######################## MODULE CONFIG ############################
59435 -ssi.extension = ( ".shtml" )
59437 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
59439 -mimetype.assign = ( ".png" => "image/png",
59440 - ".jpg" => "image/jpeg",
59441 - ".jpeg" => "image/jpeg",
59442 - ".gif" => "image/gif",
59443 - ".html" => "text/html",
59444 - ".htm" => "text/html",
59445 - ".pdf" => "application/pdf",
59446 - ".swf" => "application/x-shockwave-flash",
59447 - ".spl" => "application/futuresplash",
59448 - ".txt" => "text/plain",
59449 - ".tar.gz" => "application/x-tgz",
59450 - ".tgz" => "application/x-tgz",
59451 - ".gz" => "application/x-gzip",
59452 - ".c" => "text/plain",
59453 - ".conf" => "text/plain" )
59454 +setenv.add-request-header = ( "FOO" => "foo")
59455 +setenv.add-response-header = ( "BAR" => "foo")
59457 $HTTP["host"] == "cache.example.org" {
59458 - compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
59459 + compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
59461 -compress.filetype = ("text/plain", "text/html")
59463 -setenv.add-environment = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
59464 -setenv.add-request-header = ( "FOO" => "foo")
59465 -setenv.add-response-header = ( "BAR" => "foo")
59467 $HTTP["url"] =~ "\.pdf$" {
59468 server.range-requests = "disable"
59469 @@ -85,76 +25,43 @@
59470 "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
59474 -cgi.assign = ( ".pl" => "/usr/bin/perl",
59475 - ".cgi" => "/usr/bin/perl",
59476 - ".py" => "/usr/bin/python" )
59478 -userdir.include-user = ( "jan" )
59479 -userdir.path = "/"
59481 -ssl.engine = "disable"
59482 -ssl.pemfile = "server.pem"
59484 $HTTP["host"] == "auth-htpasswd.example.org" {
59485 auth.backend = "htpasswd"
59488 -auth.backend = "plain"
59489 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
59491 -auth.backend.htpasswd.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.htpasswd"
59494 -auth.require = ( "/server-status" =>
59496 - "method" => "digest",
59497 - "realm" => "download archiv",
59498 - "require" => "group=www|user=jan|host=192.168.2.10"
59500 - "/server-config" =>
59502 - "method" => "basic",
59503 - "realm" => "download archiv",
59504 - "require" => "valid-user"
59508 -url.access-deny = ( "~", ".inc")
59510 -url.rewrite = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
59511 - "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
59513 -expire.url = ( "/expire/access" => "access 2 hours",
59514 - "/expire/modification" => "access plus 1 seconds 2 minutes")
59516 -#cache.cache-dir = "/home/weigon/wwwroot/cache/"
59518 -#### status module
59519 -status.status-url = "/server-status"
59520 -status.config-url = "/server-config"
59522 $HTTP["host"] == "vvv.example.org" {
59523 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59524 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59525 secdownload.secret = "verysecret"
59526 - secdownload.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59527 + secdownload.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59528 secdownload.uri-prefix = "/sec/"
59529 secdownload.timeout = 120
59532 $HTTP["host"] == "zzz.example.org" {
59533 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59534 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59535 server.name = "zzz.example.org"
59538 +$HTTP["host"] == "symlink.example.org" {
59539 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59540 + server.name = "symlink.example.org"
59541 + server.follow-symlink = "enable"
59544 +$HTTP["host"] == "nosymlink.example.org" {
59545 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59546 + server.name = "symlink.example.org"
59547 + server.follow-symlink = "disable"
59550 $HTTP["host"] == "no-simple.example.org" {
59551 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/123.example.org/pages/"
59552 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/123.example.org/pages/"
59553 server.name = "zzz.example.org"
59556 $HTTP["host"] !~ "(no-simple\.example\.org)" {
59557 simple-vhost.document-root = "pages"
59558 - simple-vhost.server-root = "@SRCDIR@/tmp/lighttpd/servers/"
59559 + simple-vhost.server-root = env.SRCDIR + "/tmp/lighttpd/servers/"
59560 simple-vhost.default-host = "www.example.org"
59563 --- ../lighttpd-1.4.11/tests/lowercase.conf 1970-01-01 03:00:00.000000000 +0300
59564 +++ lighttpd-1.5.0/tests/lowercase.conf 2006-07-16 00:26:05.000000000 +0300
59566 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59567 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
59569 +## bind to port (default: 80)
59570 +server.port = 2048
59572 +## bind to localhost (default: all interfaces)
59573 +server.bind = "localhost"
59574 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
59576 +server.force-lowercase-filenames = "enable"
59578 +server.dir-listing = "enable"
59580 +server.modules = (
59583 + "mod_secdownload",
59592 +server.indexfiles = ( "index.php", "index.html",
59593 + "index.htm", "default.htm" )
59596 +######################## MODULE CONFIG ############################
59598 +mimetype.assign = ( ".png" => "image/png",
59599 + ".jpg" => "image/jpeg",
59600 + ".jpeg" => "image/jpeg",
59601 + ".gif" => "image/gif",
59602 + ".html" => "text/html",
59603 + ".htm" => "text/html",
59604 + ".pdf" => "application/pdf",
59605 + ".swf" => "application/x-shockwave-flash",
59606 + ".spl" => "application/futuresplash",
59607 + ".txt" => "text/plain",
59608 + ".tar.gz" => "application/x-tgz",
59609 + ".tgz" => "application/x-tgz",
59610 + ".gz" => "application/x-gzip",
59611 + ".c" => "text/plain",
59612 + ".conf" => "text/plain" )
59615 +fastcgi.server = ( ".php" => ( ( "host" => "127.0.0.1", "port" => 1026, "broken-scriptfilename" => "enable" ) ),
59616 + "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
59620 +cgi.assign = ( ".pl" => "/usr/bin/perl",
59621 + ".cgi" => "/usr/bin/perl",
59622 + ".py" => "/usr/bin/python" )
59624 +auth.backend = "plain"
59625 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
59627 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
59629 +$HTTP["host"] == "lowercase-auth" {
59630 + auth.require = ( "/image.jpg" =>
59632 + "method" => "digest",
59633 + "realm" => "download archiv",
59634 + "require" => "valid-user"
59639 +$HTTP["host"] == "lowercase-deny" {
59640 + url.access-deny = ( ".jpg")
59643 +$HTTP["host"] == "lowercase-exclude" {
59644 + static-file.exclude-extensions = ( ".jpg" )
59646 --- ../lighttpd-1.4.11/tests/lowercase.t 1970-01-01 03:00:00.000000000 +0300
59647 +++ lighttpd-1.5.0/tests/lowercase.t 2006-07-16 00:26:05.000000000 +0300
59649 +#!/usr/bin/env perl
59651 + # add current source dir to the include-path
59652 + # we need this for make distcheck
59653 + (my $srcdir = $0) =~ s#/[^/]+$#/#;
59654 + unshift @INC, $srcdir;
59659 +use Test::More tests => 10;
59662 +my $tf = LightyTest->new();
59665 +$tf->{CONFIGFILE} = 'lowercase.conf';
59667 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
59669 +## check if lower-casing works
59671 +$t->{REQUEST} = ( <<EOF
59672 +GET /image.JPG HTTP/1.0
59675 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
59676 +ok($tf->handle_http($t) == 0, 'uppercase access');
59678 +$t->{REQUEST} = ( <<EOF
59679 +GET /image.jpg HTTP/1.0
59682 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
59683 +ok($tf->handle_http($t) == 0, 'lowercase access');
59685 +## check that mod-auth works
59687 +$t->{REQUEST} = ( <<EOF
59688 +GET /image.JPG HTTP/1.0
59689 +Host: lowercase-auth
59692 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
59693 +ok($tf->handle_http($t) == 0, 'uppercase access');
59695 +$t->{REQUEST} = ( <<EOF
59696 +GET /image.jpg HTTP/1.0
59697 +Host: lowercase-auth
59700 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
59701 +ok($tf->handle_http($t) == 0, 'lowercase access');
59704 +## check that mod-staticfile exclude works
59705 +$t->{REQUEST} = ( <<EOF
59706 +GET /image.JPG HTTP/1.0
59707 +Host: lowercase-exclude
59710 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
59711 +ok($tf->handle_http($t) == 0, 'upper case access to staticfile.exclude-extension');
59713 +$t->{REQUEST} = ( <<EOF
59714 +GET /image.jpg HTTP/1.0
59715 +Host: lowercase-exclude
59718 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
59719 +ok($tf->handle_http($t) == 0, 'lowercase access');
59722 +## check that mod-access exclude works
59723 +$t->{REQUEST} = ( <<EOF
59724 +GET /image.JPG HTTP/1.0
59725 +Host: lowercase-deny
59728 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
59729 +ok($tf->handle_http($t) == 0, 'uppercase access to url.access-deny protected location');
59731 +$t->{REQUEST} = ( <<EOF
59732 +GET /image.jpg HTTP/1.0
59733 +Host: lowercase-deny
59736 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
59737 +ok($tf->handle_http($t) == 0, 'lowercase access');
59741 +ok($tf->stop_proc == 0, "Stopping lighttpd");
59743 --- ../lighttpd-1.4.11/tests/mod-cgi.t 2005-09-01 14:43:05.000000000 +0300
59744 +++ lighttpd-1.5.0/tests/mod-cgi.t 2006-07-18 13:03:40.000000000 +0300
59746 GET /nph-status.pl HTTP/1.0
59749 -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
59750 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 502 } ];
59751 ok($tf->handle_http($t) == 0, 'NPH + perl, Bug #14');
59753 $t->{REQUEST} = ( <<EOF
59754 --- ../lighttpd-1.4.11/tests/mod-fastcgi.t 2006-03-09 15:30:45.000000000 +0200
59755 +++ lighttpd-1.5.0/tests/mod-fastcgi.t 2006-07-18 13:03:40.000000000 +0300
59760 -use Test::More tests => 47;
59761 +use Test::More tests => 49;
59764 my $tf = LightyTest->new();
59769 - skip "no PHP running on port 1026", 30 unless $tf->listening_on(1026);
59770 + skip "no PHP running on port 1026", 29 unless $tf->listening_on(1026);
59772 ok($tf->start_proc == 0, "Starting lighttpd") or die();
59774 @@ -223,7 +223,7 @@
59778 - skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.0/sapi/cgi/php";
59779 + skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.4/sapi/cgi/php";
59780 $tf->{CONFIGFILE} = 'fastcgi-13.conf';
59781 ok($tf->start_proc == 0, "Starting lighttpd with $tf->{CONFIGFILE}") or die();
59782 $t->{REQUEST} = ( <<EOF
59783 @@ -285,6 +285,34 @@
59784 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'test123' } ];
59785 ok($tf->handle_http($t) == 0, 'line-ending \r\n + \r\n');
59787 + # X-LIGHTTPD-send-file
59788 + $t->{REQUEST} = ( <<EOF
59789 +GET /index.fcgi?x-lighttpd-send-file HTTP/1.0
59790 +Host: www.example.org
59793 + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
59795 + ok($tf->handle_http($t) == 0, 'X-LIGHTTPD-send-file');
59797 + $t->{REQUEST} = ( <<EOF
59798 +GET /index.fcgi?xsendfile HTTP/1.0
59799 +Host: www.example.org
59802 + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
59804 + ok($tf->handle_http($t) == 0, 'X-Sendfile');
59806 + $t->{REQUEST} = ( <<EOF
59807 +GET /index.fcgi?xsendfile-mixed-case HTTP/1.0
59808 +Host: www.example.org
59811 + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
59813 + ok($tf->handle_http($t) == 0, 'X-SeNdFiLe in mixed case');
59815 $t->{REQUEST} = ( <<EOF
59816 GET /index.fcgi?die-at-end HTTP/1.0
59817 Host: www.example.org
59818 --- ../lighttpd-1.4.11/tests/mod-proxy.t 1970-01-01 03:00:00.000000000 +0300
59819 +++ lighttpd-1.5.0/tests/mod-proxy.t 2006-07-18 13:03:40.000000000 +0300
59821 +#!/usr/bin/env perl
59823 + # add current source dir to the include-path
59824 + # we need this for make distcheck
59825 + (my $srcdir = $0) =~ s#/[^/]+$#/#;
59826 + unshift @INC, $srcdir;
59831 +use Test::More tests => 21;
59834 +my $tf_proxy = LightyTest->new();
59835 +my $tf_backend1 = LightyTest->new();
59836 +my $tf_backend2 = LightyTest->new();
59840 +## we need two procs
59841 +## 1. the real webserver
59842 +## 2. the proxy server
59845 + skip "disabled for now", 21;
59846 +$tf_proxy->{PORT} = 2048;
59847 +$tf_proxy->{CONFIGFILE} = 'proxy.conf';
59848 +$tf_proxy->{LIGHTTPD_PIDFILE} = $tf_proxy->{SRCDIR}.'/tmp/lighttpd/lighttpd-proxy.pid';
59850 +$tf_backend1->{PORT} = 2050;
59851 +$tf_backend1->{CONFIGFILE} = 'proxy-backend-1.conf';
59852 +$tf_backend1->{LIGHTTPD_PIDFILE} = $tf_backend1->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-1.pid';
59854 +$tf_backend2->{PORT} = 2051;
59855 +$tf_backend2->{CONFIGFILE} = 'proxy-backend-2.conf';
59856 +$tf_backend2->{LIGHTTPD_PIDFILE} = $tf_backend2->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-2.pid';
59859 +ok($tf_backend1->start_proc == 0, "Starting lighttpd") or die();
59861 +ok($tf_proxy->start_proc == 0, "Starting lighttpd as proxy") or die();
59865 +$t->{REQUEST} = ( <<EOF
59866 +GET /index.html HTTP/1.0
59867 +Host: www.example.org
59870 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
59871 +ok($tf_proxy->handle_http($t) == 0, 'valid request');
59873 +$t->{REQUEST} = ( <<EOF
59874 +GET /index.html HTTP/1.0
59875 +Host: www.example.org
59878 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Server' => 'proxy-backend-1' } ];
59879 +ok($tf_proxy->handle_http($t) == 0, 'drop Server from real server');
59881 +$t->{REQUEST} = ( <<EOF
59882 +GET /balance-rr/foo HTTP/1.0
59883 +Host: www.example.org
59886 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
59887 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one backend');
59889 +$t->{REQUEST} = ( <<EOF
59890 +GET /balance-rr/foo HTTP/1.0
59891 +Host: www.example.org
59894 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
59895 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one host down, failover');
59897 +$t->{REQUEST} = ( <<EOF
59898 +GET /balance-fair/foo HTTP/1.0
59899 +Host: www.example.org
59902 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
59903 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - one backend');
59905 +## backend 2 starting
59906 +ok($tf_backend2->start_proc == 0, "Starting second proxy backend") or die();
59908 +$t->{REQUEST} = ( <<EOF
59909 +GET /balance-rr/foo HTTP/1.0
59910 +Host: www.example.org
59913 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
59914 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 1');
59916 +$t->{REQUEST} = ( <<EOF
59917 +GET /balance-rr/foo HTTP/1.0
59918 +Host: www.example.org
59921 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
59922 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 2');
59924 +$t->{REQUEST} = ( <<EOF
59925 +GET /balance-hash/foo HTTP/1.0
59926 +Host: www.example.org
59929 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
59930 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1');
59932 +$t->{REQUEST} = ( <<EOF
59933 +GET /balance-hash/foo HTTP/1.0
59934 +Host: www.example.org
59937 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
59938 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1 - same URL');
59940 +$t->{REQUEST} = ( <<EOF
59941 +GET /balance-hash/bar HTTP/1.0
59942 +Host: www.example.org
59945 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
59946 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2');
59948 +$t->{REQUEST} = ( <<EOF
59949 +GET /balance-hash/bar HTTP/1.0
59950 +Host: www.example.org
59953 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
59954 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2 - same URL');
59956 +## backend 1 stopping, failover
59957 +ok($tf_backend1->stop_proc == 0, "Stopping backend 1");
59959 +$t->{REQUEST} = ( <<EOF
59960 +GET /balance-hash/foo HTTP/1.0
59961 +Host: www.example.org
59964 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
59965 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2');
59967 +$t->{REQUEST} = ( <<EOF
59968 +GET /balance-hash/bar HTTP/1.0
59969 +Host: www.example.org
59972 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
59973 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2 - same URL');
59975 +$t->{REQUEST} = ( <<EOF
59976 +GET /balance-rr/foo HTTP/1.0
59977 +Host: www.example.org
59980 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
59981 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - failover to backend 2');
59983 +$t->{REQUEST} = ( <<EOF
59984 +GET /balance-fair/foo HTTP/1.0
59985 +Host: www.example.org
59988 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
59989 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - failover to backend 2');
59992 +ok($tf_backend2->stop_proc == 0, "Stopping lighttpd");
59994 +ok($tf_proxy->stop_proc == 0, "Stopping lighttpd proxy");
59996 --- ../lighttpd-1.4.11/tests/proxy-backend-1.conf 1970-01-01 03:00:00.000000000 +0300
59997 +++ lighttpd-1.5.0/tests/proxy-backend-1.conf 2006-07-16 00:26:05.000000000 +0300
59999 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
60000 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-1.pid"
60002 +include "default.conf"
60005 +server.tag = "proxy-backend-1"
60006 --- ../lighttpd-1.4.11/tests/proxy-backend-2.conf 1970-01-01 03:00:00.000000000 +0300
60007 +++ lighttpd-1.5.0/tests/proxy-backend-2.conf 2006-07-16 00:26:04.000000000 +0300
60009 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
60010 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-2.pid"
60012 +include "default.conf"
60015 +server.tag = "proxy-backend-2"
60016 --- ../lighttpd-1.4.11/tests/proxy.conf 1970-01-01 03:00:00.000000000 +0300
60017 +++ lighttpd-1.5.0/tests/proxy.conf 2006-07-16 00:26:05.000000000 +0300
60019 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
60020 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd-proxy.pid"
60021 +server.tag = "proxy"
60023 +include "default.conf"
60025 +## 127.0.0.1 and 127.0.0.2 are the same host
60027 + "" => (( "host" => "127.0.0.1",
60028 + "port" => 2050 ),
60029 + ( "host" => "127.0.0.2",
60033 +$HTTP["url"] =~ "^/balance-rr/" {
60034 + proxy.balance = "round-robin"
60037 +$HTTP["url"] =~ "^/balance-hash/" {
60038 + proxy.balance = "hash"
60041 +$HTTP["url"] =~ "^/balance-fair/" {
60042 + proxy.balance = "fair"
60045 --- ../lighttpd-1.4.11/tests/request.t 2006-03-04 16:37:20.000000000 +0200
60046 +++ lighttpd-1.5.0/tests/request.t 2006-09-07 00:57:05.000000000 +0300
60047 @@ -96,12 +96,16 @@
60048 ok($tf->handle_http($t) == 0, 'HEAD request, file-not-found, query-string');
60050 $t->{REQUEST} = ( <<EOF
60055 +Host: www.example.org
60056 Expect: 100-continue
60061 -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 417, '-HTTP-Content' => ''} ];
60062 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 100} ];
60063 ok($tf->handle_http($t) == 0, 'Continue, Expect');
60066 --- ../lighttpd-1.4.11/tests/var-include.conf 2005-08-27 17:44:19.000000000 +0300
60067 +++ lighttpd-1.5.0/tests/var-include.conf 2006-07-16 00:26:05.000000000 +0300
60069 debug.log-request-handling = "enable"
60070 debug.log-condition-handling = "enable"
60072 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
60073 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
60074 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
60075 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
60077 ## bind to port (default: 80)
60080 ## bind to localhost (default: all interfaces)
60081 server.bind = "localhost"
60082 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
60083 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
60084 server.name = "www.example.org"
60085 server.tag = "Apache 1.3.29"
60087 @@ -21,19 +21,19 @@
60088 ######################## MODULE CONFIG ############################
60091 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
60092 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
60094 mimetype.assign = ( ".html" => "text/html" )
60096 url.redirect = ("^" => "/default")
60098 $HTTP["host"] == "www.example.org" {
60099 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
60100 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
60101 server.name = "www.example.org"
60102 url.redirect = ("^" => "/redirect")
60104 $HTTP["host"] == "test.example.org" {
60105 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
60106 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
60107 server.name = "test.example.org"