]> git.pld-linux.org Git - packages/lighttpd.git/blob - lighttpd-branch.diff
- svn 1210
[packages/lighttpd.git] / lighttpd-branch.diff
1 --- ../lighttpd-1.4.11/NEWS     2006-03-09 19:34:33.000000000 +0200
2 +++ lighttpd-1.4.12/NEWS        2006-07-16 00:26:05.000000000 +0300
3 @@ -3,6 +3,23 @@
4  NEWS
5  ====
6  
7 +- 1.4.12 - 2006-..-..
8 +
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
23 +
24  - 1.4.11 - 2006-03-09
25  
26    * added ability to specify which ip address spawn-fci listens on 
27 --- ../lighttpd-1.4.11/configure.in     2006-03-04 16:32:38.000000000 +0200
28 +++ lighttpd-1.4.12/configure.in        2006-07-19 20:02:55.000000000 +0300
29 @@ -1,7 +1,7 @@
30  #                                               -*- Autoconf -*-
31  # Process this file with autoconf to produce a configure script.
32  AC_PREREQ(2.57)
33 -AC_INIT(lighttpd, 1.4.11, jan@kneschke.de)
34 +AC_INIT(lighttpd, 1.4.12, jan@kneschke.de)
35  AC_CONFIG_SRCDIR([src/server.c])
36  
37  AC_CANONICAL_TARGET
38 @@ -66,7 +66,7 @@
39  AC_TYPE_PID_T
40  AC_TYPE_SIZE_T
41  
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>])
47 @@ -339,6 +339,22 @@
48      AC_DEFINE([HAVE_SQLITE3], [1], [libsqlite3])
49      AC_DEFINE([HAVE_SQLITE3_H], [1], [sqlite3.h])
50   ])
51 +
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])
56 +
57 + if test "$WITH_WEBDAV_LOCKS" != "no"; then
58 +   AC_CHECK_LIB(uuid, uuid_unparse, [
59 +         AC_CHECK_HEADERS([uuid/uuid.h],[
60 +                 UUID_LIB=-luuid
61 +                 AC_DEFINE([HAVE_UUID], [1], [libuuid])
62 +                AC_DEFINE([HAVE_UUID_H], [1], [uuid/uuid.h is available])
63 +         ])
64 + ])
65 +
66 + fi
67  fi
68  
69  dnl Check for gdbm
70 @@ -381,30 +397,11 @@
71  
72  AC_MSG_RESULT($WITH_LUA)
73  if test "$WITH_LUA" != "no"; then
74 - AC_PATH_PROG(LUACONFIG, lua-config)
75 -
76 - if test x"$LUACONFIG" != x; then
77 -   LUA_CFLAGS=`$LUACONFIG --include`
78 -   LUA_LIBS=`$LUACONFIG --libs --extralibs`
79 + # try pkgconfig
80 + PKG_CHECK_MODULES(LUA, lua >= 5.1, [
81     AC_DEFINE([HAVE_LUA], [1], [liblua])
82     AC_DEFINE([HAVE_LUA_H], [1], [lua.h])
83 - else
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])
89 -     ])
90 -   ])
91 - fi
92 -
93 - if test x"$LUA_LIBS" = x; then
94 -   # try pkgconfig
95 -   PKG_CHECK_MODULES(LUA, lua, [
96 -     AC_DEFINE([HAVE_LUA], [1], [liblua])
97 -     AC_DEFINE([HAVE_LUA_H], [1], [lua.h])
98 -   ])
99 - fi
100 + ])
101  
102   AC_SUBST(LUA_CFLAGS)
103   AC_SUBST(LUA_LIBS)
104 @@ -440,8 +437,8 @@
105  esac
106  
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])
114  
115 @@ -519,7 +516,7 @@
116  
117  
118  if test "${GCC}" = "yes"; then
119 -       CFLAGS="${CFLAGS} -Wall -W -Wshadow -pedantic"
120 +       CFLAGS="${CFLAGS} -Wall -W -Wshadow -pedantic -std=gnu99"
121  fi
122  
123  dnl build version-id
124 @@ -538,7 +535,7 @@
125  AC_OUTPUT
126  
127  
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" 
130  
131  plugins="mod_rewrite mod_redirect mod_ssi mod_trigger_b4_dl"
132  features="regex-conditionals"
133 @@ -642,6 +639,14 @@
134         disable_feature="$disable_feature $features"
135  fi
136  
137 +features="webdav-locks"
138 +if test "x$UUID_LIB" \!= x; then
139 +       enable_feature="$enable_feature $features"
140 +else
141 +       disable_feature="$disable_feature $features"
142 +fi
143 +
144 +
145  ## output
146  
147  $ECHO
148 --- ../lighttpd-1.4.11/cygwin/lighttpd.README   2006-03-07 14:22:19.000000000 +0200
149 +++ lighttpd-1.4.12/cygwin/lighttpd.README      2006-07-19 20:09:00.000000000 +0300
150 @@ -1,114 +1,114 @@
151 -lighttpd\r
152 -------------------------------------------\r
153 -A fast, secure and flexible webserver\r
154 -\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
162 -\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
167 -  crypt\r
168 -  openssl-devel\r
169 -  openssl\r
170 -  openldap\r
171 -  openldap-devel\r
172 -  zlib\r
173 -  bzip2\r
174 -\r
175 -Canonical homepage:\r
176 -  http://jan.kneschke.de/projects/lighttpd/\r
177 -\r
178 -Canonical download:\r
179 -  http://jan.kneschke.de/projects/lighttpd/download\r
180 -\r
181 -------------------------------------\r
182 -\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
187 -  cd /usr/src\r
188 -  ./lighttpd-1.4.11-<REL>.sh all\r
189 -\r
190 -This will create:\r
191 -  /usr/src/lighttpd-1.4.11-<REL>.tar.bz2\r
192 -  /usr/src/lighttpd-1.4.11-<REL>-src.tar.bz2\r
193 -\r
194 -Or use './lighttpd-1.4.11-<REL>.sh prep' to get a patched source directory\r
195 -\r
196 --------------------------------------------\r
197 -\r
198 -Files included in the binary distribution:\r
199 -\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
250 -\r
251 -------------------\r
252 -\r
253 -Port Notes:\r
254 -\r
255 -----------  lighttpd-1.3.1-1 -----------\r
256 -\r
257 -Updated to 1.3.1\r
258 -\r
259 -----------  lighttpd-1.3.0-1 -----------\r
260 -Initial release\r
261 -\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
264 -\r
265 +lighttpd
266 +------------------------------------------
267 +A fast, secure and flexible webserver
268 +
269 +Runtime requirements:
270 +  cygwin-1.5.10 or newer
271 +  crypt-1.1 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
276 +
277 +Build requirements:
278 +  cygwin-1.5.10 or newer
279 +  gcc-3.3.1-3 or newer
280 +  binutils-20030901-1 or newer
281 +  crypt
282 +  openssl-devel
283 +  openssl
284 +  openldap
285 +  openldap-devel
286 +  zlib
287 +  bzip2
288 +
289 +Canonical homepage:
290 +  http://jan.kneschke.de/projects/lighttpd/
291 +
292 +Canonical download:
293 +  http://jan.kneschke.de/projects/lighttpd/download
294 +
295 +------------------------------------
296 +
297 +Build instructions:
298 +  unpack lighttpd-1.4.12-<REL>-src.tar.bz2
299 +    if you use setup to install this src package, it will be
300 +        unpacked under /usr/src automatically
301 +  cd /usr/src
302 +  ./lighttpd-1.4.12-<REL>.sh all
303 +
304 +This will create:
305 +  /usr/src/lighttpd-1.4.12-<REL>.tar.bz2
306 +  /usr/src/lighttpd-1.4.12-<REL>-src.tar.bz2
307 +
308 +Or use './lighttpd-1.4.12-<REL>.sh prep' to get a patched source directory
309 +
310 +-------------------------------------------
311 +
312 +Files included in the binary distribution:
313 +
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
364 +
365 +------------------
366 +
367 +Port Notes:
368 +
369 +----------  lighttpd-1.3.1-1 -----------
370 +
371 +Updated to 1.3.1
372 +
373 +----------  lighttpd-1.3.0-1 -----------
374 +Initial release
375 +
376 +Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
377 +Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
378 +
379 --- ../lighttpd-1.4.11/cygwin/lighttpd.README.in        2005-08-11 01:26:59.000000000 +0300
380 +++ lighttpd-1.4.12/cygwin/lighttpd.README.in   2006-07-16 00:26:04.000000000 +0300
381 @@ -1,114 +1,114 @@
382 -lighttpd\r
383 -------------------------------------------\r
384 -A fast, secure and flexible webserver\r
385 -\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
393 -\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
398 -  crypt\r
399 -  openssl-devel\r
400 -  openssl\r
401 -  openldap\r
402 -  openldap-devel\r
403 -  zlib\r
404 -  bzip2\r
405 -\r
406 -Canonical homepage:\r
407 -  http://jan.kneschke.de/projects/lighttpd/\r
408 -\r
409 -Canonical download:\r
410 -  http://jan.kneschke.de/projects/lighttpd/download\r
411 -\r
412 -------------------------------------\r
413 -\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
418 -  cd /usr/src\r
419 -  ./lighttpd-@VERSION@-<REL>.sh all\r
420 -\r
421 -This will create:\r
422 -  /usr/src/lighttpd-@VERSION@-<REL>.tar.bz2\r
423 -  /usr/src/lighttpd-@VERSION@-<REL>-src.tar.bz2\r
424 -\r
425 -Or use './lighttpd-@VERSION@-<REL>.sh prep' to get a patched source directory\r
426 -\r
427 --------------------------------------------\r
428 -\r
429 -Files included in the binary distribution:\r
430 -\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
481 -\r
482 -------------------\r
483 -\r
484 -Port Notes:\r
485 -\r
486 -----------  lighttpd-1.3.1-1 -----------\r
487 -\r
488 -Updated to 1.3.1\r
489 -\r
490 -----------  lighttpd-1.3.0-1 -----------\r
491 -Initial release\r
492 -\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
495 -\r
496 +lighttpd
497 +------------------------------------------
498 +A fast, secure and flexible webserver
499 +
500 +Runtime requirements:
501 +  cygwin-1.5.10 or newer
502 +  crypt-1.1 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
507 +
508 +Build requirements:
509 +  cygwin-1.5.10 or newer
510 +  gcc-3.3.1-3 or newer
511 +  binutils-20030901-1 or newer
512 +  crypt
513 +  openssl-devel
514 +  openssl
515 +  openldap
516 +  openldap-devel
517 +  zlib
518 +  bzip2
519 +
520 +Canonical homepage:
521 +  http://jan.kneschke.de/projects/lighttpd/
522 +
523 +Canonical download:
524 +  http://jan.kneschke.de/projects/lighttpd/download
525 +
526 +------------------------------------
527 +
528 +Build instructions:
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
532 +  cd /usr/src
533 +  ./lighttpd-@VERSION@-<REL>.sh all
534 +
535 +This will create:
536 +  /usr/src/lighttpd-@VERSION@-<REL>.tar.bz2
537 +  /usr/src/lighttpd-@VERSION@-<REL>-src.tar.bz2
538 +
539 +Or use './lighttpd-@VERSION@-<REL>.sh prep' to get a patched source directory
540 +
541 +-------------------------------------------
542 +
543 +Files included in the binary distribution:
544 +
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
595 +
596 +------------------
597 +
598 +Port Notes:
599 +
600 +----------  lighttpd-1.3.1-1 -----------
601 +
602 +Updated to 1.3.1
603 +
604 +----------  lighttpd-1.3.0-1 -----------
605 +Initial release
606 +
607 +Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
608 +Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
609 +
610 --- ../lighttpd-1.4.11/doc/authentication.txt   2006-01-12 20:34:26.000000000 +0200
611 +++ lighttpd-1.4.12/doc/authentication.txt      2006-07-16 00:26:05.000000000 +0300
612 @@ -7,8 +7,8 @@
613  ----------------
614  
615  :Author: Jan Kneschke
616 -:Date: $Date$
617 -:Revision: $Revision$
618 +:Date: $Date$
619 +:Revision: $Revision$
620  
621  :abstract:
622    The auth module provides ...
623 --- ../lighttpd-1.4.11/doc/compress.txt 2005-08-11 01:26:16.000000000 +0300
624 +++ lighttpd-1.4.12/doc/compress.txt    2006-07-16 00:26:05.000000000 +0300
625 @@ -22,12 +22,38 @@
626  ===========
627  
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.
633  
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
637 +text-browsers.
638  
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.
642 +
643 +Caching
644 +-------
645 +
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
648 +compressed. 
649 +
650 +The names of the cache files are made of the filename, the compression method
651 +and the etag associated to the file.
652 +
653 +Cleaning the cache is left to the user. A cron job deleting files older than
654 +10 days should do fine.
655 +
656 +Limitations
657 +-----------
658 +
659 +The module limits the compression of files to files larger than 128 Byte and
660 +smaller than 128 MByte.
661 +
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.
665  
666  Options
667  =======
668 @@ -47,15 +73,28 @@
669    Default: not set, compress the file for every request
670  
671  compress.filetype
672 -  mimetypes where might get compressed
673 +  mimetypes which might get compressed
674    
675    e.g.: ::
676    
677      compress.filetype           = ("text/plain", "text/html")
678  
679 +  Keep in mind that compressed JavaScript and CSS files are broken in some
680 +  browsers.
681 +
682    Default: not set
683  
684 +compress.max-file-size 
685 +  maximum size of the original file to be compressed kBytes.
686 +
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
689 +  of the server.
690  
691 +  There is a hard upper limit of 128Mbyte.
692 +
693 +  Default: unlimited (== hard-limit of 128MByte)
694 +  
695  Compressing Dynamic Content
696  ===========================
697  
698 --- ../lighttpd-1.4.11/doc/configuration.txt    2006-03-09 02:10:40.000000000 +0200
699 +++ lighttpd-1.4.12/doc/configuration.txt       2006-07-16 00:26:05.000000000 +0300
700 @@ -7,8 +7,8 @@
701  ------------
702  
703  :Author: Jan Kneschke
704 -:Date: $Date$
705 -:Revision: $Revision$
706 +:Date: $Date$
707 +:Revision: $Revision$
708  
709  :abstract:
710    the layout of the configuration file
711 @@ -511,3 +511,10 @@
712  
713  debug.log-request-handling
714    default: disabled 
715 +
716 +debug.log-condition-handling
717 +  default: disabled 
718 +
719 +debug.log-condition-cache-handling
720 +  for developers only
721 +  default: disabled 
722 --- ../lighttpd-1.4.11/doc/fastcgi.txt  2006-02-16 17:03:52.000000000 +0200
723 +++ lighttpd-1.4.12/doc/fastcgi.txt     2006-07-16 00:26:05.000000000 +0300
724 @@ -144,8 +144,8 @@
725                  PHP can extract PATH_INFO from it (default: disabled)
726    :"disable-time": time to wait before a disabled backend is checked
727                  again
728 -  :"allow-x-send-file": controls if X-LIGHTTPD-send-file headers
729 -                are allowed 
730 +  :"allow-x-send-file": controls if X-LIGHTTPD-send-file and X-Sendfile
731 +                headers are allowed 
732  
733    If bin-path is set:
734  
735 --- ../lighttpd-1.4.11/doc/lighttpd.conf        2006-03-04 14:41:12.000000000 +0200
736 +++ lighttpd-1.4.12/doc/lighttpd.conf   2006-07-16 00:26:05.000000000 +0300
737 @@ -172,10 +172,11 @@
738  #dir-listing.activate       = "enable"
739  
740  ## enable debugging
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"
750  
751  ### only root can use these options
752  #
753 --- ../lighttpd-1.4.11/doc/performance.txt      2006-02-02 13:01:08.000000000 +0200
754 +++ lighttpd-1.4.12/doc/performance.txt 2006-07-16 00:26:05.000000000 +0300
755 @@ -183,6 +183,8 @@
756  
757    server.stat-cache-engine = "fam"   # either fam, simple or disabled
758  
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.
761  
762  Platform-Specific Notes
763  =======================
764 --- ../lighttpd-1.4.11/doc/secdownload.txt      2005-12-20 15:58:58.000000000 +0200
765 +++ lighttpd-1.4.12/doc/secdownload.txt 2006-07-16 00:26:05.000000000 +0300
766 @@ -118,7 +118,7 @@
767    $secret = "verysecret";
768    $uri_prefix = "/dl/";
769    
770 -  # filename
771 +  # filename, make sure it's started with a "/" or you'll get 404 in the browser
772    $f = "/secret-file.txt";
773    
774    # current timestamp
775 --- ../lighttpd-1.4.11/lighttpd.spec    2006-03-07 14:22:18.000000000 +0200
776 +++ lighttpd-1.4.12/lighttpd.spec       2006-07-19 20:09:00.000000000 +0300
777 @@ -1,6 +1,6 @@
778  Summary: A fast webserver with minimal memory-footprint (lighttpd)
779  Name: lighttpd
780 -Version: 1.4.11
781 +Version: 1.4.12
782  Release: 1
783  Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-%version.tar.gz
784  Packager: Jan Kneschke <jan@kneschke.de>
785 --- ../lighttpd-1.4.11/openwrt/control  2006-03-07 14:22:19.000000000 +0200
786 +++ lighttpd-1.4.12/openwrt/control     2006-07-19 20:09:00.000000000 +0300
787 @@ -1,8 +1,8 @@
788  Package: lighttpd
789 -Version: 1.4.11
790 +Version: 1.4.12
791  Architecture: mipsel
792  Maintainer: Jan Kneschke <jan@kneschke.de>
793 -Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.11.tar.gz
794 +Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.12.tar.gz
795  Section: net
796  Priority: optional
797  Depends:
798 --- ../lighttpd-1.4.11/openwrt/lighttpd.mk      2006-03-07 14:22:19.000000000 +0200
799 +++ lighttpd-1.4.12/openwrt/lighttpd.mk 2006-07-19 20:09:00.000000000 +0300
800 @@ -10,7 +10,7 @@
801  
802  #  For this example we'll use a fairly simple package that compiles easily
803  #  and has sources available for download at sourceforge
804 -LIGHTTPD=lighttpd-1.4.11
805 +LIGHTTPD=lighttpd-1.4.12
806  LIGHTTPD_TARGET=.built
807  LIGHTTPD_DIR=$(BUILD_DIR)/$(LIGHTTPD)
808  LIGHTTPD_IPK=$(BUILD_DIR)/$(LIGHTTPD)_mipsel.ipk
809 --- ../lighttpd-1.4.11/src/Makefile.am  2006-03-07 14:20:20.000000000 +0200
810 +++ lighttpd-1.4.12/src/Makefile.am     2006-07-19 20:02:55.000000000 +0300
811 @@ -16,18 +16,24 @@
812  else
813  configparser.y: lemon
814  mod_ssi_exprparser.y: lemon
815 +http_resp_parser.y: lemon
816  
817  configparser.c configparser.h: configparser.y
818         rm -f configparser.h
819 -       $(LEMON) -q $(srcdir)/configparser.y $(srcdir)/lempar.c
820 +       $(LEMON) -q $(srcdir)/$< $(srcdir)/lempar.c
821 +
822 +http_resp_parser.c http_resp_parser.h: http_resp_parser.y
823 +       rm -f http_resp_parser.h
824 +       $(LEMON) -q $(srcdir)/$< $(srcdir)/lempar.c
825  
826  mod_ssi_exprparser.c mod_ssi_exprparser.h: mod_ssi_exprparser.y 
827         rm -f mod_ssi_exprparser.h
828 -       $(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c
829 +       $(LEMON) -q $(srcdir)/$< $(srcdir)/lempar.c
830  endif
831  
832  configfile.c: configparser.h
833  mod_ssi_expr.c: mod_ssi_exprparser.h
834 +http_resp.c: http_resp_parser.h
835  
836  common_src=buffer.c log.c \
837        keyvalue.c chunk.c  \
838 @@ -40,13 +46,13 @@
839        fdevent_solaris_devpoll.c fdevent_freebsd_kqueue.c \
840        data_config.c bitset.c \
841        inet_ntop_cache.c crc32.c \
842 -      connections-glue.c \
843 -      configfile-glue.c \
844 +      connections-glue.c iosocket.c \
845 +      configfile-glue.c status_counter.c \
846        http-header-glue.c \
847        network_write.c network_linux_sendfile.c \
848        network_freebsd_sendfile.c network_writev.c \
849        network_solaris_sendfilev.c network_openssl.c \
850 -      splaytree.c 
851 +      splaytree.c http_resp.c http_resp_parser.c 
852        
853  src = server.c response.c connections.c network.c \
854        configfile.c configparser.c request.c proc_open.c
855 @@ -82,9 +88,9 @@
856  
857  lib_LTLIBRARIES += mod_webdav.la
858  mod_webdav_la_SOURCES = mod_webdav.c
859 -mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS)
860 +mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS) 
861  mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
862 -mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS)
863 +mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) $(UUID_LIB)
864  
865  lib_LTLIBRARIES += mod_cml.la
866  mod_cml_la_SOURCES = mod_cml.c mod_cml_lua.c mod_cml_funcs.c
867 @@ -103,6 +109,11 @@
868  mod_mysql_vhost_la_LIBADD = $(MYSQL_LIBS) $(common_libadd)
869  mod_mysql_vhost_la_CPPFLAGS = $(MYSQL_INCLUDE)
870  
871 +lib_LTLIBRARIES += mod_sql_vhost_core.la
872 +mod_sql_vhost_core_la_SOURCES = mod_sql_vhost_core.c
873 +mod_sql_vhost_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
874 +mod_sql_vhost_core_la_LIBADD = $(common_libadd)
875 +
876  lib_LTLIBRARIES += mod_cgi.la
877  mod_cgi_la_SOURCES = mod_cgi.c 
878  mod_cgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
879 @@ -158,6 +169,14 @@
880  mod_proxy_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
881  mod_proxy_la_LIBADD = $(common_libadd)
882  
883 +lib_LTLIBRARIES += mod_proxy_core.la
884 +mod_proxy_core_la_SOURCES = mod_proxy_core.c mod_proxy_core_pool.c \
885 +                           mod_proxy_core_backend.c mod_proxy_core_address.c \
886 +                           mod_proxy_core_backlog.c mod_proxy_core_rewrites.c
887 +mod_proxy_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
888 +mod_proxy_core_la_LIBADD = $(common_libadd) $(PCRE_LIB)
889 +
890 +
891  lib_LTLIBRARIES += mod_ssi.la
892  mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c 
893  mod_ssi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
894 @@ -240,7 +259,13 @@
895        mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
896        configparser.h mod_ssi_exprparser.h \
897        sys-mmap.h sys-socket.h mod_cml.h mod_cml_funcs.h \
898 -      splaytree.h proc_open.h
899 +      splaytree.h proc_open.h http_resp.h mod_sql_vhost_core.h \
900 +      sys-files.h sys-process.h sys-strings.h http_resp_parser.h \
901 +      iosocket.h array-static.h \
902 +      mod_proxy_core_address.h mod_proxy_core_backend.h \
903 +      mod_proxy_core_backlog.h mod_proxy_core.h  \
904 +      mod_proxy_core_pool.h mod_proxy_core_rewrites.h \
905 +      status_counter.h
906  
907  DEFS= @DEFS@ -DLIBRARY_DIR="\"$(libdir)\""
908  
909 @@ -267,4 +292,4 @@
910  #ajp_SOURCES = ajp.c
911  
912  noinst_HEADERS   = $(hdr)
913 -EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c
914 +EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c http_resp_parser.y
915 --- ../lighttpd-1.4.11/src/array-static.h       1970-01-01 03:00:00.000000000 +0300
916 +++ lighttpd-1.4.12/src/array-static.h  2006-07-18 13:03:40.000000000 +0300
917 @@ -0,0 +1,33 @@
918 +#ifndef _ARRAY_STATIC_H_
919 +#define _ARRAY_STATIC_H_
920 +
921 +/* define a generic array of <type>
922 + * */
923 +
924 +#define ARRAY_STATIC_DEF(name, type, extra) \
925 +typedef struct { \
926 +       type **ptr; \
927 +       size_t used; \
928 +       size_t size; \
929 +       extra\
930 +} name
931 +
932 +/* all append operations need a 'resize' for the +1 */
933 +
934 +#define ARRAY_STATIC_PREPARE_APPEND(a) \
935 +        if (a->size == 0) { \
936 +               a->size = 16; \
937 +               a->ptr = malloc(a->size * sizeof(*(a->ptr))); \
938 +       } else if (a->size == a->used) { \
939 +               a->size += 16; \
940 +               a->ptr = realloc(a->ptr, a->size * sizeof(*(a->ptr))); \
941 +       }
942 +       
943 +#define FOREACH(array, element, func) \
944 +do { size_t _i; for (_i = 0; _i < array->used; _i++) { void *element = array->ptr[_i]; func; } } while(0);
945 +
946 +#define STRUCT_INIT(type, var) \
947 +       type *var;\
948 +       var = calloc(1, sizeof(*var))
949 +
950 +#endif
951 --- ../lighttpd-1.4.11/src/array.c      2005-11-18 13:58:32.000000000 +0200
952 +++ lighttpd-1.4.12/src/array.c 2006-07-16 00:26:03.000000000 +0300
953 @@ -11,12 +11,12 @@
954  
955  array *array_init(void) {
956         array *a;
957 -       
958 +
959         a = calloc(1, sizeof(*a));
960         assert(a);
961 -       
962 +
963         a->next_power_of_2 = 1;
964 -       
965 +
966         return a;
967  }
968  
969 @@ -43,29 +43,29 @@
970  void array_free(array *a) {
971         size_t i;
972         if (!a) return;
973 -       
974 +
975         if (!a->is_weakref) {
976                 for (i = 0; i < a->size; i++) {
977                         if (a->data[i]) a->data[i]->free(a->data[i]);
978                 }
979         }
980 -       
981 +
982         if (a->data) free(a->data);
983         if (a->sorted) free(a->sorted);
984 -       
985 +
986         free(a);
987  }
988  
989  void array_reset(array *a) {
990         size_t i;
991         if (!a) return;
992 -       
993 +
994         if (!a->is_weakref) {
995                 for (i = 0; i < a->used; i++) {
996                         a->data[i]->reset(a->data[i]);
997                 }
998         }
999 -       
1000 +
1001         a->used = 0;
1002  }
1003  
1004 @@ -84,20 +84,20 @@
1005  static int array_get_index(array *a, const char *key, size_t keylen, int *rndx) {
1006         int ndx = -1;
1007         int i, pos = 0;
1008 -       
1009 +
1010         if (key == NULL) return -1;
1011 -       
1012 +
1013         /* try to find the string */
1014         for (i = pos = a->next_power_of_2 / 2; ; i >>= 1) {
1015                 int cmp;
1016 -               
1017 +
1018                 if (pos < 0) {
1019                         pos += i;
1020                 } else if (pos >= (int)a->used) {
1021                         pos -= i;
1022                 } else {
1023                         cmp = buffer_caseless_compare(key, keylen, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used);
1024 -                       
1025 +
1026                         if (cmp == 0) {
1027                                 /* found */
1028                                 ndx = a->sorted[pos];
1029 @@ -110,46 +110,46 @@
1030                 }
1031                 if (i == 0) break;
1032         }
1033 -       
1034 +
1035         if (rndx) *rndx = pos;
1036 -       
1037 +
1038         return ndx;
1039  }
1040  
1041  data_unset *array_get_element(array *a, const char *key) {
1042         int ndx;
1043 -       
1044 +
1045         if (-1 != (ndx = array_get_index(a, key, strlen(key) + 1, NULL))) {
1046                 /* found, leave here */
1047 -               
1048 +
1049                 return a->data[ndx];
1050 -       } 
1051 -       
1052 +       }
1053 +
1054         return NULL;
1055  }
1056  
1057  data_unset *array_get_unused_element(array *a, data_type_t t) {
1058         data_unset *ds = NULL;
1059 -       
1060 +
1061         UNUSED(t);
1062  
1063         if (a->size == 0) return NULL;
1064 -       
1065 +
1066         if (a->used == a->size) return NULL;
1067  
1068         if (a->data[a->used]) {
1069                 ds = a->data[a->used];
1070 -               
1071 +
1072                 a->data[a->used] = NULL;
1073         }
1074 -       
1075 +
1076         return ds;
1077  }
1078  
1079  /* replace or insert data, return the old one with the same key */
1080  data_unset *array_replace(array *a, data_unset *du) {
1081         int ndx;
1082 -       
1083 +
1084         if (-1 == (ndx = array_get_index(a, du->key->ptr, du->key->used, NULL))) {
1085                 array_insert_unique(a, du);
1086                 return NULL;
1087 @@ -164,13 +164,13 @@
1088         int ndx = -1;
1089         int pos = 0;
1090         size_t j;
1091 -       
1092 -       /* generate unique index if neccesary */
1093 +
1094 +       /* generate unique index if necessary */
1095         if (str->key->used == 0 || str->is_index_key) {
1096                 buffer_copy_long(str->key, a->unique_ndx++);
1097                 str->is_index_key = 1;
1098         }
1099 -       
1100 +
1101         /* try to find the string */
1102         if (-1 != (ndx = array_get_index(a, str->key->ptr, str->key->used, &pos))) {
1103                 /* found, leave here */
1104 @@ -181,14 +181,14 @@
1105                 }
1106                 return 0;
1107         }
1108 -       
1109 +
1110         /* insert */
1111 -       
1112 +
1113         if (a->used+1 > INT_MAX) {
1114                 /* we can't handle more then INT_MAX entries: see array_get_index() */
1115                 return -1;
1116         }
1117 -       
1118 +
1119         if (a->size == 0) {
1120                 a->size   = 16;
1121                 a->data   = malloc(sizeof(*a->data)     * a->size);
1122 @@ -204,27 +204,27 @@
1123                 assert(a->sorted);
1124                 for (j = a->used; j < a->size; j++) a->data[j] = NULL;
1125         }
1126 -       
1127 +
1128         ndx = (int) a->used;
1129 -       
1130 +
1131         a->data[a->used++] = str;
1132 -       
1133 +
1134         if (pos != ndx &&
1135 -           ((pos < 0) || 
1136 +           ((pos < 0) ||
1137              buffer_caseless_compare(str->key->ptr, str->key->used, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used) > 0)) {
1138                 pos++;
1139 -       } 
1140 -       
1141 -       /* move everything on step to the right */
1142 +       }
1143 +
1144 +       /* move everything one step to the right */
1145         if (pos != ndx) {
1146                 memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted));
1147         }
1148 -       
1149 +
1150         /* insert */
1151         a->sorted[pos] = ndx;
1152 -       
1153 +
1154         if (a->next_power_of_2 == (size_t)ndx) a->next_power_of_2 <<= 1;
1155 -       
1156 +
1157         return 0;
1158  }
1159  
1160 @@ -254,7 +254,7 @@
1161         size_t i;
1162         size_t maxlen;
1163         int oneline = 1;
1164 -       
1165 +
1166         if (a->used > 5) {
1167                 oneline = 0;
1168         }
1169 @@ -314,7 +314,7 @@
1170         }
1171         array_print_indent(depth);
1172         fprintf(stderr, ")");
1173 -       
1174 +
1175         return 0;
1176  }
1177  
1178 @@ -323,47 +323,47 @@
1179         array *a;
1180         data_string *ds;
1181         data_count *dc;
1182 -       
1183 +
1184         UNUSED(argc);
1185         UNUSED(argv);
1186  
1187         a = array_init();
1188 -       
1189 +
1190         ds = data_string_init();
1191         buffer_copy_string(ds->key, "abc");
1192         buffer_copy_string(ds->value, "alfrag");
1193 -       
1194 +
1195         array_insert_unique(a, (data_unset *)ds);
1196 -       
1197 +
1198         ds = data_string_init();
1199         buffer_copy_string(ds->key, "abc");
1200         buffer_copy_string(ds->value, "hameplman");
1201 -       
1202 +
1203         array_insert_unique(a, (data_unset *)ds);
1204 -       
1205 +
1206         ds = data_string_init();
1207         buffer_copy_string(ds->key, "123");
1208         buffer_copy_string(ds->value, "alfrag");
1209 -       
1210 +
1211         array_insert_unique(a, (data_unset *)ds);
1212 -       
1213 +
1214         dc = data_count_init();
1215         buffer_copy_string(dc->key, "def");
1216 -       
1217 +
1218         array_insert_unique(a, (data_unset *)dc);
1219 -       
1220 +
1221         dc = data_count_init();
1222         buffer_copy_string(dc->key, "def");
1223 -       
1224 +
1225         array_insert_unique(a, (data_unset *)dc);
1226 -       
1227 +
1228         array_print(a, 0);
1229 -       
1230 +
1231         array_free(a);
1232 -       
1233 +
1234         fprintf(stderr, "%d\n",
1235                buffer_caseless_compare(CONST_STR_LEN("Content-Type"), CONST_STR_LEN("Content-type")));
1236 -       
1237 +
1238         return 0;
1239  }
1240  #endif
1241 --- ../lighttpd-1.4.11/src/array.h      2005-09-23 21:24:18.000000000 +0300
1242 +++ lighttpd-1.4.12/src/array.h 2006-07-16 00:26:03.000000000 +0300
1243 @@ -16,7 +16,7 @@
1244  #define DATA_UNSET \
1245         data_type_t type; \
1246         buffer *key; \
1247 -       int is_index_key; /* 1 if key is a array index (autogenerated keys) */ \
1248 +       int is_index_key; /* 1 if key is an array index (auto-generated keys) */ \
1249         struct data_unset *(*copy)(const struct data_unset *src); \
1250         void (* free)(struct data_unset *p); \
1251         void (* reset)(struct data_unset *p); \
1252 @@ -29,21 +29,21 @@
1253  
1254  typedef struct {
1255         data_unset  **data;
1256 -       
1257 +
1258         size_t *sorted;
1259 -       
1260 +
1261         size_t used;
1262         size_t size;
1263 -       
1264 +
1265         size_t unique_ndx;
1266 -       
1267 +
1268         size_t next_power_of_2;
1269         int is_weakref; /* data is weakref, don't bother the data */
1270  } array;
1271  
1272  typedef struct {
1273         DATA_UNSET;
1274 -       
1275 +
1276         int count;
1277  } data_count;
1278  
1279 @@ -51,7 +51,7 @@
1280  
1281  typedef struct {
1282         DATA_UNSET;
1283 -       
1284 +
1285         buffer *value;
1286  } data_string;
1287  
1288 @@ -60,7 +60,7 @@
1289  
1290  typedef struct {
1291         DATA_UNSET;
1292 -       
1293 +
1294         array *value;
1295  } data_array;
1296  
1297 @@ -74,7 +74,7 @@
1298         COMP_SERVER_SOCKET, COMP_HTTP_URL, COMP_HTTP_HOST, COMP_HTTP_REFERER, COMP_HTTP_USERAGENT, COMP_HTTP_COOKIE, COMP_HTTP_REMOTEIP
1299  } comp_key_t;
1300  
1301 -/* $HTTP["host"] ==    "incremental.home.kneschke.de" { ... } 
1302 +/* $HTTP["host"] ==    "incremental.home.kneschke.de" { ... }
1303   * for print:   comp_key      op    string
1304   * for compare: comp          cond  string/regex
1305   */
1306 @@ -82,15 +82,15 @@
1307  typedef struct _data_config data_config;
1308  struct _data_config {
1309         DATA_UNSET;
1310 -       
1311 +
1312         array *value;
1313 -       
1314 +
1315         buffer *comp_key;
1316         comp_key_t comp;
1317 -       
1318 +
1319         config_cond_t cond;
1320         buffer *op;
1321 -       
1322 +
1323         int context_ndx; /* more or less like an id */
1324         array *childs;
1325         /* nested */
1326 @@ -98,7 +98,7 @@
1327         /* for chaining only */
1328         data_config *prev;
1329         data_config *next;
1330 -       
1331 +
1332         buffer *string;
1333  #ifdef HAVE_PCRE_H
1334         pcre   *regex;
1335 @@ -110,7 +110,7 @@
1336  
1337  typedef struct {
1338         DATA_UNSET;
1339 -       
1340 +
1341         int value;
1342  } data_integer;
1343  
1344 @@ -120,13 +120,13 @@
1345         DATA_UNSET;
1346  
1347         buffer *host;
1348 -       
1349 +
1350         unsigned short port;
1351  
1352         time_t disable_ts;
1353         int is_disabled;
1354         size_t balance;
1355 -               
1356 +
1357         int usage; /* fair-balancing needs the no. of connections active on this host */
1358         int last_used_ndx; /* round robin */
1359  } data_fastcgi;
1360 --- ../lighttpd-1.4.11/src/base.h       2006-01-11 16:51:04.000000000 +0200
1361 +++ lighttpd-1.4.12/src/base.h  2006-07-19 20:02:55.000000000 +0300
1362 @@ -2,7 +2,6 @@
1363  #define _BASE_H_
1364  
1365  #include <sys/types.h>
1366 -#include <sys/time.h>
1367  #include <sys/stat.h>
1368  
1369  #ifdef HAVE_CONFIG_H
1370 @@ -26,10 +25,9 @@
1371  #include "sys-socket.h"
1372  #include "splaytree.h"
1373  
1374 -
1375  #if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
1376  # define USE_OPENSSL
1377 -# include <openssl/ssl.h> 
1378 +# include <openssl/ssl.h>
1379  #endif
1380  
1381  #ifdef HAVE_FAM_H
1382 @@ -40,10 +38,6 @@
1383  # define O_BINARY 0
1384  #endif
1385  
1386 -#ifndef O_LARGEFILE
1387 -# define O_LARGEFILE 0
1388 -#endif
1389 -
1390  #ifndef SIZE_MAX
1391  # ifdef SIZE_T_MAX
1392  #  define SIZE_MAX SIZE_T_MAX
1393 @@ -70,7 +64,8 @@
1394  
1395  /* solaris and NetBSD 1.3.x again */
1396  #if (!defined(HAVE_STDINT_H)) && (!defined(HAVE_INTTYPES_H)) && (!defined(uint32_t))
1397 -# define uint32_t u_int32_t
1398 +/* # define uint32_t u_int32_t */
1399 +typedef unsigned __int32 uint32_t;
1400  #endif
1401  
1402  
1403 @@ -80,24 +75,24 @@
1404  
1405  #include "settings.h"
1406  
1407 -typedef enum { T_CONFIG_UNSET, 
1408 -               T_CONFIG_STRING, 
1409 -               T_CONFIG_SHORT, 
1410 -               T_CONFIG_BOOLEAN, 
1411 -               T_CONFIG_ARRAY, 
1412 -               T_CONFIG_LOCAL, 
1413 +typedef enum { T_CONFIG_UNSET,
1414 +               T_CONFIG_STRING,
1415 +               T_CONFIG_SHORT,
1416 +               T_CONFIG_BOOLEAN,
1417 +               T_CONFIG_ARRAY,
1418 +               T_CONFIG_LOCAL,
1419                 T_CONFIG_DEPRECATED
1420  } config_values_type_t;
1421  
1422 -typedef enum { T_CONFIG_SCOPE_UNSET, 
1423 -               T_CONFIG_SCOPE_SERVER, 
1424 +typedef enum { T_CONFIG_SCOPE_UNSET,
1425 +               T_CONFIG_SCOPE_SERVER,
1426                 T_CONFIG_SCOPE_CONNECTION
1427  } config_scope_type_t;
1428  
1429  typedef struct {
1430         const char *key;
1431         void *destination;
1432 -       
1433 +
1434         config_values_type_t type;
1435         config_scope_type_t scope;
1436  } config_values_t;
1437 @@ -118,18 +113,6 @@
1438         short factor;
1439  } fcgi_connections;
1440  
1441 -
1442 -typedef union {
1443 -#ifdef HAVE_IPV6
1444 -       struct sockaddr_in6 ipv6;
1445 -#endif
1446 -       struct sockaddr_in ipv4;
1447 -#ifdef HAVE_SYS_UN_H
1448 -       struct sockaddr_un un;
1449 -#endif
1450 -       struct sockaddr plain;
1451 -} sock_addr;
1452 -
1453  /* fcgi_response_header contains ... */
1454  #define HTTP_STATUS         BV(0)
1455  #define HTTP_CONNECTION     BV(1)
1456 @@ -142,40 +125,40 @@
1457         /* the request-line */
1458         buffer *request;
1459         buffer *uri;
1460 -       
1461 +
1462         buffer *orig_uri;
1463 -       
1464 +
1465         http_method_t  http_method;
1466         http_version_t http_version;
1467 -       
1468 +
1469         buffer *request_line;
1470 -       
1471 +
1472         /* strings to the header */
1473         buffer *http_host; /* not alloced */
1474         const char   *http_range;
1475         const char   *http_content_type;
1476         const char   *http_if_modified_since;
1477         const char   *http_if_none_match;
1478 -       
1479 +
1480         array  *headers;
1481 -       
1482 +
1483         /* CONTENT */
1484         size_t content_length; /* returned by strtoul() */
1485 -       
1486 +
1487         /* internal representation */
1488         int     accept_encoding;
1489 -       
1490 +
1491         /* internal */
1492         buffer *pathinfo;
1493  } request;
1494  
1495  typedef struct {
1496         off_t   content_length;
1497 -       int     keep_alive;               /* used by  the subrequests in proxy, cgi and fcgi to say the subrequest was keep-alive or not */
1498 -       
1499 +       int     keep_alive;               /* used by the subrequests in proxy, cgi and fcgi to say whether the subrequest was keep-alive or not */
1500 +
1501         array  *headers;
1502 -       
1503 -       enum { 
1504 +
1505 +       enum {
1506                 HTTP_TRANSFER_ENCODING_IDENTITY, HTTP_TRANSFER_ENCODING_CHUNKED
1507         } transfer_encoding;
1508  } response;
1509 @@ -191,21 +174,21 @@
1510  typedef struct {
1511         buffer *path;
1512         buffer *basedir; /* path = "(basedir)(.*)" */
1513 -       
1514 +
1515         buffer *doc_root; /* path = doc_root + rel_path */
1516         buffer *rel_path;
1517 -       
1518 +
1519         buffer *etag;
1520  } physical;
1521  
1522  typedef struct {
1523         buffer *name;
1524         buffer *etag;
1525 -       
1526 +
1527         struct stat st;
1528 -       
1529 +
1530         time_t stat_ts;
1531 -       
1532 +
1533  #ifdef HAVE_FAM_H
1534         int    dir_version;
1535         int    dir_ndx;
1536 @@ -215,20 +198,20 @@
1537  } stat_cache_entry;
1538  
1539  typedef struct {
1540 -       splay_tree *files; /* the nodes of the tree are stat_cache_entry's */
1541 -       
1542 +       splay_tree *files; /* the nodes of the tree are stat_cache_entries */
1543 +
1544         buffer *dir_name; /* for building the dirname from the filename */
1545  #ifdef HAVE_FAM_H
1546         splay_tree *dirs; /* the nodes of the tree are fam_dir_entry */
1547  
1548         FAMConnection *fam;
1549 -       int    fam_fcce_ndx;
1550 +       iosocket *sock;
1551  #endif
1552  } stat_cache;
1553  
1554  typedef struct {
1555         array *mimetypes;
1556 -       
1557 +
1558         /* virtual-servers */
1559         buffer *document_root;
1560         buffer *server_name;
1561 @@ -236,7 +219,7 @@
1562         buffer *server_tag;
1563         buffer *dirlist_encoding;
1564         buffer *errorfile_prefix;
1565 -       
1566 +
1567         unsigned short max_keep_alive_requests;
1568         unsigned short max_keep_alive_idle;
1569         unsigned short max_read_idle;
1570 @@ -244,16 +227,17 @@
1571         unsigned short use_xattr;
1572         unsigned short follow_symlink;
1573         unsigned short range_requests;
1574 -       
1575 +
1576         /* debug */
1577 -       
1578 +
1579         unsigned short log_file_not_found;
1580         unsigned short log_request_header;
1581         unsigned short log_request_handling;
1582         unsigned short log_response_header;
1583         unsigned short log_condition_handling;
1584 -       
1585 -       
1586 +       unsigned short log_condition_cache_handling;
1587 +
1588 +
1589         /* server wide */
1590         buffer *ssl_pemfile;
1591         buffer *ssl_ca_file;
1592 @@ -268,22 +252,22 @@
1593         /* configside */
1594         unsigned short global_kbytes_per_second; /*  */
1595  
1596 -       off_t  global_bytes_per_second_cnt; 
1597 +       off_t  global_bytes_per_second_cnt;
1598         /* server-wide traffic-shaper
1599 -        * 
1600 +        *
1601          * each context has the counter which is inited once
1602 -        * a second by the global_kbytes_per_second config-var
1603 +        * per second by the global_kbytes_per_second config-var
1604          *
1605          * as soon as global_kbytes_per_second gets below 0
1606          * the connected conns are "offline" a little bit
1607          *
1608          * the problem:
1609 -        * we somehow have to loose our "we are writable" signal 
1610 +        * we somehow have to lose our "we are writable" signal
1611          * on the way.
1612 -        * 
1613 +        *
1614          */
1615         off_t *global_bytes_per_second_cnt_ptr; /*  */
1616 -       
1617 +
1618  #ifdef USE_OPENSSL
1619         SSL_CTX *ssl_ctx;
1620  #endif
1621 @@ -291,18 +275,18 @@
1622  
1623  /* the order of the items should be the same as they are processed
1624   * read before write as we use this later */
1625 -typedef enum { 
1626 -       CON_STATE_CONNECT, 
1627 -       CON_STATE_REQUEST_START, 
1628 -       CON_STATE_READ, 
1629 -       CON_STATE_REQUEST_END, 
1630 -       CON_STATE_READ_POST, 
1631 -       CON_STATE_HANDLE_REQUEST, 
1632 -       CON_STATE_RESPONSE_START, 
1633 -       CON_STATE_WRITE, 
1634 -       CON_STATE_RESPONSE_END, 
1635 -       CON_STATE_ERROR, 
1636 -       CON_STATE_CLOSE 
1637 +typedef enum {
1638 +       CON_STATE_CONNECT,
1639 +       CON_STATE_REQUEST_START,
1640 +       CON_STATE_READ,
1641 +       CON_STATE_REQUEST_END,
1642 +       CON_STATE_READ_POST,
1643 +       CON_STATE_HANDLE_REQUEST,
1644 +       CON_STATE_RESPONSE_START,
1645 +       CON_STATE_WRITE,
1646 +       CON_STATE_RESPONSE_END,
1647 +       CON_STATE_ERROR,
1648 +       CON_STATE_CLOSE
1649  } connection_state_t;
1650  
1651  typedef enum { COND_RESULT_UNSET, COND_RESULT_FALSE, COND_RESULT_TRUE } cond_result_t;
1652 @@ -315,91 +299,86 @@
1653  
1654  typedef struct {
1655         connection_state_t state;
1656 -       
1657 +
1658         /* timestamps */
1659         time_t read_idle_ts;
1660         time_t close_timeout_ts;
1661         time_t write_request_ts;
1662 -       
1663 +
1664         time_t connection_start;
1665         time_t request_start;
1666 -       
1667 +
1668         struct timeval start_tv;
1669 -       
1670 +
1671         size_t request_count;        /* number of requests handled in this connection */
1672         size_t loops_per_request;    /* to catch endless loops in a single request
1673 -                                     * 
1674 +                                     *
1675                                       * used by mod_rewrite, mod_fastcgi, ... and others
1676                                       * this is self-protection
1677                                       */
1678 -       
1679 -       int fd;                      /* the FD for this connection */
1680 -       int fde_ndx;                 /* index for the fdevent-handler */
1681 +
1682 +       iosocket *sock;
1683         int ndx;                     /* reverse mapping to server->connection[ndx] */
1684 -       
1685 +
1686         /* fd states */
1687         int is_readable;
1688         int is_writable;
1689 -       
1690 -       int     keep_alive;           /* only request.c can enable it, all other just disable */
1691 -       
1692 +
1693 +       int     keep_alive;           /* only request.c can enable it, all others just disable */
1694 +
1695         int file_started;
1696         int file_finished;
1697 -       
1698 +
1699         chunkqueue *write_queue;      /* a large queue for low-level write ( HTTP response ) [ file, mem ] */
1700         chunkqueue *read_queue;       /* a small queue for low-level read ( HTTP request ) [ mem ] */
1701         chunkqueue *request_content_queue; /* takes request-content into tempfile if necessary [ tempfile, mem ]*/
1702 -       
1703 +
1704         int traffic_limit_reached;
1705 -       
1706 +
1707         off_t bytes_written;          /* used by mod_accesslog, mod_rrd */
1708         off_t bytes_written_cur_second; /* used by mod_accesslog, mod_rrd */
1709         off_t bytes_read;             /* used by mod_accesslog, mod_rrd */
1710         off_t bytes_header;
1711 -       
1712 +
1713         int http_status;
1714 -       
1715 +
1716         sock_addr dst_addr;
1717         buffer *dst_addr_buf;
1718  
1719         /* request */
1720         buffer *parse_request;
1721         unsigned int parsed_response; /* bitfield which contains the important header-fields of the parsed response header */
1722 -       
1723 +
1724         request  request;
1725         request_uri uri;
1726 -       physical physical; 
1727 +       physical physical;
1728         response response;
1729 -       
1730 +
1731         size_t header_len;
1732 -       
1733 +
1734         buffer *authed_user;
1735         array  *environment; /* used to pass lighttpd internal stuff to the FastCGI/CGI apps, setenv does that */
1736 -       
1737 +
1738         /* response */
1739         int    got_response;
1740 -       
1741 +
1742         int    in_joblist;
1743 -       
1744 +
1745         connection_type mode;
1746 -       
1747 +
1748         void **plugin_ctx;           /* plugin connection specific config */
1749 -       
1750 +
1751         specific_config conf;        /* global connection specific config */
1752         cond_cache_t *cond_cache;
1753 -       
1754 +
1755         buffer *server_name;
1756 -       
1757 +
1758         /* error-handler */
1759         buffer *error_handler;
1760         int error_handler_saved_status;
1761         int in_error_handler;
1762 -       
1763 +
1764         void *srv_socket;   /* reference to the server-socket (typecast to server_socket) */
1765 -       
1766 -#ifdef USE_OPENSSL
1767 -       SSL *ssl;
1768 -#endif
1769  } connection;
1770  
1771  typedef struct {
1772 @@ -439,55 +418,63 @@
1773         size_t size;
1774  } buffer_plugin;
1775  
1776 +typedef enum {
1777 +    NETWORK_STATUS_UNSET,
1778 +    NETWORK_STATUS_SUCCESS,
1779 +    NETWORK_STATUS_FATAL_ERROR,
1780 +    NETWORK_STATUS_CONNECTION_CLOSE,
1781 +    NETWORK_STATUS_WAIT_FOR_EVENT,
1782 +    NETWORK_STATUS_INTERRUPTED
1783 +} network_status_t;
1784 +
1785  typedef struct {
1786         unsigned short port;
1787         buffer *bindhost;
1788 -       
1789 -       buffer *errorlog_file;
1790 -       unsigned short errorlog_use_syslog;
1791 -       
1792 +
1793         unsigned short dont_daemonize;
1794         buffer *changeroot;
1795         buffer *username;
1796         buffer *groupname;
1797 -       
1798 +
1799         buffer *pid_file;
1800 -       
1801 +
1802         buffer *event_handler;
1803 -       
1804 +
1805         buffer *modules_dir;
1806         buffer *network_backend;
1807         array *modules;
1808         array *upload_tempdirs;
1809 -       
1810 +
1811         unsigned short max_worker;
1812         unsigned short max_fds;
1813         unsigned short max_conns;
1814         unsigned short max_request_size;
1815 -       
1816 +
1817         unsigned short log_request_header_on_error;
1818         unsigned short log_state_handling;
1819 -       
1820 -       enum { STAT_CACHE_ENGINE_UNSET, 
1821 -                       STAT_CACHE_ENGINE_NONE, 
1822 -                       STAT_CACHE_ENGINE_SIMPLE, 
1823 -                       STAT_CACHE_ENGINE_FAM 
1824 +
1825 +       enum { STAT_CACHE_ENGINE_UNSET,
1826 +                       STAT_CACHE_ENGINE_NONE,
1827 +                       STAT_CACHE_ENGINE_SIMPLE,
1828 +                       STAT_CACHE_ENGINE_FAM
1829         } stat_cache_engine;
1830         unsigned short enable_cores;
1831 +
1832 +       buffer *errorlog_file;
1833 +       unsigned short errorlog_use_syslog;
1834  } server_config;
1835  
1836  typedef struct {
1837         sock_addr addr;
1838 -       int       fd;
1839 -       int       fde_ndx;
1840 -       
1841 +       iosocket *sock;
1842 +
1843         buffer *ssl_pemfile;
1844         buffer *ssl_ca_file;
1845         unsigned short use_ipv6;
1846         unsigned short is_ssl;
1847 -       
1848 +
1849         buffer *srv_token;
1850 -       
1851 +
1852  #ifdef USE_OPENSSL
1853         SSL_CTX *ssl_ctx;
1854  #endif
1855 @@ -495,37 +482,32 @@
1856  
1857  typedef struct {
1858         server_socket **ptr;
1859 -       
1860 +
1861         size_t size;
1862         size_t used;
1863  } server_socket_array;
1864  
1865  typedef struct server {
1866         server_socket_array srv_sockets;
1867 -       
1868 -       /* the errorlog */
1869 -       int errorlog_fd;
1870 -       enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } errorlog_mode;
1871 -       buffer *errorlog_buf;
1872 -       
1873 +
1874         fdevents *ev, *ev_ins;
1875 -       
1876 +
1877         buffer_plugin plugins;
1878         void *plugin_slots;
1879 -       
1880 +
1881         /* counters */
1882         int con_opened;
1883         int con_read;
1884         int con_written;
1885         int con_closed;
1886 -       
1887 +
1888         int ssl_is_init;
1889 -       
1890 +
1891         int max_fds;    /* max possible fds */
1892         int cur_fds;    /* currently used fds */
1893         int want_fds;   /* waiting fds */
1894         int sockets_disabled;
1895 -       
1896 +
1897         size_t max_conns;
1898  
1899         /* buffers */
1900 @@ -533,13 +515,13 @@
1901         buffer *response_header;
1902         buffer *response_range;
1903         buffer *tmp_buf;
1904 -       
1905 +
1906         buffer *tmp_chunk_len;
1907 -       
1908 +
1909         buffer *empty_string; /* is necessary for cond_match */
1910  
1911         buffer *cond_check_buf;
1912 -       
1913 +
1914         /* caches */
1915  #ifdef HAVE_IPV6
1916         inet_ntop_cache_type inet_ntop_cache[INET_NTOP_CACHE_MAX];
1917 @@ -547,59 +529,46 @@
1918         mtime_cache_type mtime_cache[FILE_CACHE_MAX];
1919  
1920         array *split_vals;
1921 -       
1922 +
1923         /* Timestamps */
1924         time_t cur_ts;
1925         time_t last_generated_date_ts;
1926         time_t last_generated_debug_ts;
1927         time_t startup_ts;
1928 -       
1929 +
1930         buffer *ts_debug_str;
1931         buffer *ts_date_str;
1932 -       
1933 +
1934         /* config-file */
1935         array *config;
1936         array *config_touched;
1937 -       
1938 +
1939         array *config_context;
1940         specific_config **config_storage;
1941 -       
1942 +
1943         server_config  srvconf;
1944 -       
1945 +
1946         int config_deprecated;
1947 -       
1948 +
1949         connections *conns;
1950         connections *joblist;
1951         connections *fdwaitqueue;
1952 -       
1953 +
1954         stat_cache  *stat_cache;
1955  
1956 -       /**
1957 -        * The status array can carry all the status information you want
1958 -        * the key to the array is <module-prefix>.<name>
1959 -        * and the values are counters
1960 -        *
1961 -        * example:
1962 -        *   fastcgi.backends        = 10
1963 -        *   fastcgi.active-backends = 6
1964 -        *   fastcgi.backend.<key>.load = 24
1965 -        *   fastcgi.backend.<key>....
1966 -        *
1967 -        *   fastcgi.backend.<key>.disconnects = ...
1968 -        */
1969 -       array *status;
1970 -       
1971         fdevent_handler_t event_handler;
1972  
1973 -       int (* network_backend_write)(struct server *srv, connection *con, int fd, chunkqueue *cq);
1974 -       int (* network_backend_read)(struct server *srv, connection *con, int fd, chunkqueue *cq);
1975 +       network_status_t (* network_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1976 +       network_status_t (* network_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1977  #ifdef USE_OPENSSL
1978 -       int (* network_ssl_backend_write)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
1979 -       int (* network_ssl_backend_read)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
1980 +       network_status_t (* network_ssl_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1981 +       network_status_t (* network_ssl_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1982  #endif
1983  
1984 +#ifdef HAVE_PWD_H
1985         uid_t uid;
1986         gid_t gid;
1987 +#endif
1988  } server;
1989  
1990  
1991 --- ../lighttpd-1.4.11/src/bitset.c     2005-08-22 01:54:12.000000000 +0300
1992 +++ lighttpd-1.4.12/src/bitset.c        2006-07-18 13:03:40.000000000 +0300
1993 @@ -6,6 +6,7 @@
1994  
1995  #include "bitset.h"
1996  #include "buffer.h"
1997 +#include "log.h"
1998  
1999  #define BITSET_BITS \
2000         ( CHAR_BIT * sizeof(size_t) )
2001 --- ../lighttpd-1.4.11/src/buffer.c     2006-01-13 00:00:45.000000000 +0200
2002 +++ lighttpd-1.4.12/src/buffer.c        2006-07-18 13:03:40.000000000 +0300
2003 @@ -12,20 +12,20 @@
2004  
2005  
2006  /**
2007 - * init the buffer 
2008 - * 
2009 + * init the buffer
2010 + *
2011   */
2012  
2013  buffer* buffer_init(void) {
2014         buffer *b;
2015 -       
2016 +
2017         b = malloc(sizeof(*b));
2018         assert(b);
2019 -       
2020 +
2021         b->ptr = NULL;
2022         b->size = 0;
2023         b->used = 0;
2024 -       
2025 +
2026         return b;
2027  }
2028  
2029 @@ -36,8 +36,8 @@
2030  }
2031  
2032  /**
2033 - * free the buffer 
2034 - * 
2035 + * free the buffer
2036 + *
2037   */
2038  
2039  void buffer_free(buffer *b) {
2040 @@ -49,39 +49,39 @@
2041  
2042  void buffer_reset(buffer *b) {
2043         if (!b) return;
2044 -       
2045 +
2046         /* limit don't reuse buffer larger than ... bytes */
2047         if (b->size > BUFFER_MAX_REUSE_SIZE) {
2048                 free(b->ptr);
2049                 b->ptr = NULL;
2050                 b->size = 0;
2051         }
2052 -       
2053 +
2054         b->used = 0;
2055  }
2056  
2057  
2058  /**
2059 - * 
2060 - * allocate (if neccessary) enough space for 'size' bytes and 
2061 + *
2062 + * allocate (if necessary) enough space for 'size' bytes and
2063   * set the 'used' counter to 0
2064 - * 
2065 + *
2066   */
2067  
2068  #define BUFFER_PIECE_SIZE 64
2069  
2070  int buffer_prepare_copy(buffer *b, size_t size) {
2071         if (!b) return -1;
2072 -       
2073 -       if ((0 == b->size) || 
2074 +
2075 +       if ((0 == b->size) ||
2076             (size > b->size)) {
2077                 if (b->size) free(b->ptr);
2078 -               
2079 +
2080                 b->size = size;
2081 -               
2082 -               /* always allocate a multiply of BUFFER_PIECE_SIZE */
2083 +
2084 +               /* always allocate a multiple of BUFFER_PIECE_SIZE */
2085                 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2086 -               
2087 +
2088                 b->ptr = malloc(b->size);
2089                 assert(b->ptr);
2090         }
2091 @@ -90,30 +90,30 @@
2092  }
2093  
2094  /**
2095 - * 
2096 - * increase the internal buffer (if neccessary) to append another 'size' byte
2097 + *
2098 + * increase the internal buffer (if necessary) to append another 'size' byte
2099   * ->used isn't changed
2100 - * 
2101 + *
2102   */
2103  
2104  int buffer_prepare_append(buffer *b, size_t size) {
2105         if (!b) return -1;
2106 -       
2107 +
2108         if (0 == b->size) {
2109                 b->size = size;
2110 -               
2111 -               /* always allocate a multiply of BUFFER_PIECE_SIZE */
2112 +
2113 +               /* always allocate a multiple of BUFFER_PIECE_SIZE */
2114                 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2115 -               
2116 +
2117                 b->ptr = malloc(b->size);
2118                 b->used = 0;
2119                 assert(b->ptr);
2120         } else if (b->used + size > b->size) {
2121                 b->size += size;
2122 -               
2123 -               /* always allocate a multiply of BUFFER_PIECE_SIZE */
2124 +
2125 +               /* always allocate a multiple of BUFFER_PIECE_SIZE */
2126                 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2127 -               
2128 +
2129                 b->ptr = realloc(b->ptr, b->size);
2130                 assert(b->ptr);
2131         }
2132 @@ -122,7 +122,7 @@
2133  
2134  int buffer_copy_string(buffer *b, const char *s) {
2135         size_t s_len;
2136 -       
2137 +
2138         if (!s || !b) return -1;
2139  
2140         s_len = strlen(s) + 1;
2141 @@ -136,26 +136,26 @@
2142  
2143  int buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
2144         if (!s || !b) return -1;
2145 -#if 0  
2146 -       /* removed optimization as we have to keep the empty string 
2147 +#if 0
2148 +       /* removed optimization as we have to keep the empty string
2149          * in some cases for the config handling
2150 -        * 
2151 +        *
2152          * url.access-deny = ( "" )
2153          */
2154         if (s_len == 0) return 0;
2155 -#endif 
2156 +#endif
2157         buffer_prepare_copy(b, s_len + 1);
2158 -       
2159 +
2160         memcpy(b->ptr, s, s_len);
2161         b->ptr[s_len] = '\0';
2162         b->used = s_len + 1;
2163 -       
2164 +
2165         return 0;
2166  }
2167  
2168  int buffer_copy_string_buffer(buffer *b, const buffer *src) {
2169         if (!src) return -1;
2170 -       
2171 +
2172         if (src->used == 0) {
2173                 b->used = 0;
2174                 return 0;
2175 @@ -201,10 +201,10 @@
2176  
2177  /**
2178   * append a string to the end of the buffer
2179 - * 
2180 - * the resulting buffer is terminated with a '\0' 
2181 - * s is treated as a un-terminated string (a \0 is handled a normal character)
2182 - * 
2183 + *
2184 + * the resulting buffer is terminated with a '\0'
2185 + * s is treated as an un-terminated string (a \0 is handled as a normal character)
2186 + *
2187   * @param b a buffer
2188   * @param s the string
2189   * @param s_len size of the string (without the terminating \0)
2190 @@ -228,7 +228,7 @@
2191  int buffer_append_string_buffer(buffer *b, const buffer *src) {
2192         if (!src) return -1;
2193         if (src->used == 0) return 0;
2194 -       
2195 +
2196         return buffer_append_string_len(b, src->ptr, src->used - 1);
2197  }
2198  
2199 @@ -245,9 +245,9 @@
2200  
2201  int buffer_copy_memory(buffer *b, const char *s, size_t s_len) {
2202         if (!s || !b) return -1;
2203 -       
2204 +
2205         b->used = 0;
2206 -       
2207 +
2208         return buffer_append_memory(b, s, s_len);
2209  }
2210  
2211 @@ -402,46 +402,115 @@
2212  
2213  
2214  /**
2215 - * init the buffer 
2216 - * 
2217 + * init the ptr buffer
2218 + *
2219 + */
2220 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer)
2221 +{
2222 +       buffer_ptr *l = calloc(1, sizeof(buffer_ptr));
2223 +       l->free = freer;
2224 +
2225 +       return l;
2226 +}
2227 +
2228 +/**
2229 + * free the buffer_array
2230 + *
2231 + */
2232 +void buffer_ptr_free(buffer_ptr *l)
2233 +{
2234 +       if (NULL != l) {
2235 +               buffer_ptr_clear(l);
2236 +               free(l);
2237 +       }
2238 +}
2239 +
2240 +void buffer_ptr_clear(buffer_ptr *l)
2241 +{
2242 +       assert(NULL != l);
2243 +
2244 +       if (l->free && l->used) {
2245 +               size_t i;
2246 +               for (i = 0; i < l->used; i ++) {
2247 +                       l->free(l->ptr[i]);
2248 +               }
2249 +       }
2250 +
2251 +       if (l->ptr) {
2252 +               free(l->ptr);
2253 +               l->ptr = NULL;
2254 +       }
2255 +       l->used = 0;
2256 +       l->size = 0;
2257 +}
2258 +
2259 +void buffer_ptr_append(buffer_ptr* l, void *item)
2260 +{
2261 +       assert(NULL != l);
2262 +       if (l->ptr == NULL) {
2263 +               l->size = 16;
2264 +               l->ptr = (void **)malloc(sizeof(void *) * l->size);
2265 +       }
2266 +       else if (l->used == l->size) {
2267 +               l->size += 16;
2268 +               l->ptr = realloc(l->ptr, sizeof(void *) * l->size);
2269 +       }
2270 +       l->ptr[l->used++] = item;
2271 +}
2272 +
2273 +void *buffer_ptr_pop(buffer_ptr* l)
2274 +{
2275 +       assert(NULL != l && l->used > 0);
2276 +       return l->ptr[--l->used];
2277 +}
2278 +
2279 +void *buffer_ptr_top(buffer_ptr* l)
2280 +{
2281 +       assert(NULL != l && l->used > 0);
2282 +       return l->ptr[l->used-1];
2283 +}
2284 +
2285 +/**
2286 + * init the buffer
2287 + *
2288   */
2289  
2290  buffer_array* buffer_array_init(void) {
2291         buffer_array *b;
2292 -       
2293 +
2294         b = malloc(sizeof(*b));
2295 -       
2296 +
2297         assert(b);
2298         b->ptr = NULL;
2299         b->size = 0;
2300         b->used = 0;
2301 -       
2302 +
2303         return b;
2304  }
2305  
2306  void buffer_array_reset(buffer_array *b) {
2307         size_t i;
2308 -       
2309 +
2310         if (!b) return;
2311 -       
2312 +
2313         /* if they are too large, reduce them */
2314         for (i = 0; i < b->used; i++) {
2315                 buffer_reset(b->ptr[i]);
2316         }
2317 -       
2318 +
2319         b->used = 0;
2320  }
2321  
2322  
2323  /**
2324 - * free the buffer_array 
2325 - * 
2326 + * free the buffer_array
2327 + *
2328   */
2329  
2330  void buffer_array_free(buffer_array *b) {
2331         size_t i;
2332         if (!b) return;
2333 -       
2334 +
2335         for (i = 0; i < b->size; i++) {
2336                 if (b->ptr[i]) buffer_free(b->ptr[i]);
2337         }
2338 @@ -451,7 +520,7 @@
2339  
2340  buffer *buffer_array_append_get_buffer(buffer_array *b) {
2341         size_t i;
2342 -       
2343 +
2344         if (b->size == 0) {
2345                 b->size = 16;
2346                 b->ptr = malloc(sizeof(*b->ptr) * b->size);
2347 @@ -467,13 +536,13 @@
2348                         b->ptr[i] = NULL;
2349                 }
2350         }
2351 -       
2352 +
2353         if (b->ptr[b->used] == NULL) {
2354                 b->ptr[b->used] = buffer_init();
2355         }
2356 -       
2357 +
2358         b->ptr[b->used]->used = 0;
2359 -       
2360 +
2361         return b->ptr[b->used++];
2362  }
2363  
2364 @@ -482,23 +551,23 @@
2365         size_t i;
2366         if (len == 0) return NULL;
2367         if (needle == NULL) return NULL;
2368 -       
2369 +
2370         if (b->used < len) return NULL;
2371 -       
2372 +
2373         for(i = 0; i < b->used - len; i++) {
2374                 if (0 == memcmp(b->ptr + i, needle, len)) {
2375                         return b->ptr + i;
2376                 }
2377         }
2378 -       
2379 +
2380         return NULL;
2381  }
2382  
2383  buffer *buffer_init_string(const char *str) {
2384         buffer *b = buffer_init();
2385 -       
2386 +
2387         buffer_copy_string(b, str);
2388 -       
2389 +
2390         return b;
2391  }
2392  
2393 @@ -507,8 +576,8 @@
2394  }
2395  
2396  /**
2397 - * check if two buffer contain the same data
2398 - * 
2399 + * check if two buffers contain the same data
2400 + *
2401   * HISTORY: this function was pretty much optimized, but didn't handled
2402   * alignment properly.
2403   */
2404 @@ -517,105 +586,105 @@
2405         if (a->used != b->used) return 0;
2406         if (a->used == 0) return 1;
2407  
2408 -       return (0 == strcmp(a->ptr, b->ptr));
2409 +       return (0 == strncmp(a->ptr, b->ptr, a->used - 1));
2410  }
2411  
2412  int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {
2413         buffer b;
2414 -       
2415 +
2416         b.ptr = (char *)s;
2417         b.used = b_len + 1;
2418 -       
2419 +
2420         return buffer_is_equal(a, &b);
2421  }
2422  
2423  /* simple-assumption:
2424 - * 
2425 - * most parts are equal and doing a case conversion needs time
2426 - * 
2427 + *
2428 + * most parts are equal and doing a case conversion takes time
2429 + *
2430   */
2431  int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len) {
2432         size_t ndx = 0, max_ndx;
2433         size_t *al, *bl;
2434         size_t mask = sizeof(*al) - 1;
2435 -       
2436 +
2437         al = (size_t *)a;
2438         bl = (size_t *)b;
2439 -       
2440 -       /* is the alignment correct ? */
2441 +
2442 +       /* is the alignment correct? */
2443         if ( ((size_t)al & mask) == 0 &&
2444              ((size_t)bl & mask) == 0 ) {
2445 -               
2446 +
2447                 max_ndx = ((a_len < b_len) ? a_len : b_len) & ~mask;
2448 -               
2449 +
2450                 for (; ndx < max_ndx; ndx += sizeof(*al)) {
2451                         if (*al != *bl) break;
2452                         al++; bl++;
2453 -                       
2454 +
2455                 }
2456 -               
2457 +
2458         }
2459 -       
2460 +
2461         a = (char *)al;
2462         b = (char *)bl;
2463 -       
2464 +
2465         max_ndx = ((a_len < b_len) ? a_len : b_len);
2466 -       
2467 +
2468         for (; ndx < max_ndx; ndx++) {
2469                 char a1 = *a++, b1 = *b++;
2470 -               
2471 +
2472                 if (a1 != b1) {
2473                         if ((a1 >= 'A' && a1 <= 'Z') && (b1 >= 'a' && b1 <= 'z'))
2474                                 a1 |= 32;
2475                         else if ((a1 >= 'a' && a1 <= 'z') && (b1 >= 'A' && b1 <= 'Z'))
2476                                 b1 |= 32;
2477                         if ((a1 - b1) != 0) return (a1 - b1);
2478 -                       
2479 +
2480                 }
2481         }
2482 -       
2483 +
2484         return 0;
2485  }
2486  
2487  
2488  /**
2489   * check if the rightmost bytes of the string are equal.
2490 - * 
2491 - * 
2492 + *
2493 + *
2494   */
2495  
2496  int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
2497         /* no, len -> equal */
2498         if (len == 0) return 1;
2499 -       
2500 +
2501         /* len > 0, but empty buffers -> not equal */
2502         if (b1->used == 0 || b2->used == 0) return 0;
2503 -       
2504 +
2505         /* buffers too small -> not equal */
2506 -       if (b1->used - 1 < len || b1->used - 1 < len) return 0;
2507 -       
2508 -       if (0 == strncmp(b1->ptr + b1->used - 1 - len, 
2509 +       if (b1->used - 1 < len || b2->used - 1 < len) return 0;
2510 +
2511 +       if (0 == strncmp(b1->ptr + b1->used - 1 - len,
2512                          b2->ptr + b2->used - 1 - len, len)) {
2513                 return 1;
2514         }
2515 -       
2516 +
2517         return 0;
2518  }
2519  
2520  int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
2521         size_t i;
2522 -       
2523 +
2524         /* BO protection */
2525         if (in_len * 2 < in_len) return -1;
2526 -       
2527 +
2528         buffer_prepare_copy(b, in_len * 2 + 1);
2529 -       
2530 +
2531         for (i = 0; i < in_len; i++) {
2532                 b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F];
2533                 b->ptr[b->used++] = hex_chars[in[i] & 0x0F];
2534         }
2535         b->ptr[b->used++] = '\0';
2536 -       
2537 +
2538         return 0;
2539  }
2540  
2541 @@ -624,7 +693,7 @@
2542         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2543         */
2544         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2545 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2546 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2547         1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1,  /*  20 -  2F space " # $ % & ' + , / */
2548         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; = ? @ < > */
2549         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2550 @@ -646,7 +715,7 @@
2551         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2552         */
2553         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2554 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2555 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2556         1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0,  /*  20 -  2F space " # $ % & ' + , / */
2557         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; = ? @ < > */
2558         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2559 @@ -668,7 +737,7 @@
2560         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2561         */
2562         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2563 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2564 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2565         0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */
2566         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
2567         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2568 @@ -690,7 +759,7 @@
2569         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2570         */
2571         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2572 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2573 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2574         0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */
2575         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
2576         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2577 @@ -712,12 +781,12 @@
2578         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2579         */
2580         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2581 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2582 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  20 -  2F */ 
2583 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  30 -  3F */ 
2584 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  40 -  4F */ 
2585 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  50 -  5F */ 
2586 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  60 -  6F */ 
2587 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2588 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  20 -  2F */
2589 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  30 -  3F */
2590 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  40 -  4F */
2591 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  50 -  5F */
2592 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  60 -  6F */
2593         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  70 -  7F */
2594         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
2595         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
2596 @@ -734,13 +803,12 @@
2597         unsigned char *ds, *d;
2598         size_t d_len, ndx;
2599         const char *map = NULL;
2600 -       
2601 +
2602         if (!s || !b) return -1;
2603 -       
2604 -       if (b->ptr[b->used - 1] != '\0') {
2605 -               SEGFAULT();
2606 -       }
2607 -       
2608 +       if (b->used == 0) return -1;
2609 +
2610 +       if (b->ptr[b->used - 1] != '\0') return -1;
2611 +
2612         if (s_len == 0) return 0;
2613  
2614         switch(encoding) {
2615 @@ -760,12 +828,12 @@
2616                 map = encoded_chars_hex;
2617                 break;
2618         case ENCODING_UNSET:
2619 -               break;
2620 +               return buffer_append_string_len(b, s, s_len);
2621         }
2622  
2623         assert(map != NULL);
2624 -       
2625 -       /* count to-be-encoded-characters */
2626 +
2627 +       /* count to-be-encoded characters */
2628         for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2629                 if (map[*ds]) {
2630                         switch(encoding) {
2631 @@ -787,9 +855,9 @@
2632                         d_len ++;
2633                 }
2634         }
2635 -       
2636 +
2637         buffer_prepare_append(b, d_len);
2638 -       
2639 +
2640         for (ds = (unsigned char *)s, d = (unsigned char *)b->ptr + b->used - 1, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2641                 if (map[*ds]) {
2642                         switch(encoding) {
2643 @@ -820,16 +888,16 @@
2644                 }
2645         }
2646  
2647 -       /* terminate buffer and calculate new length */ 
2648 +       /* terminate buffer and calculate new length */
2649         b->ptr[b->used + d_len - 1] = '\0';
2650 -       
2651 +
2652         b->used += d_len;
2653  
2654         return 0;
2655  }
2656  
2657  
2658 -/* decodes url-special-chars inplace.
2659 +/* decodes url-special chars in-place.
2660   * replaces non-printable characters with '_'
2661   */
2662  
2663 @@ -854,10 +922,10 @@
2664                                 low = hex2int(*(src + 2));
2665                                 if (low != 0xFF) {
2666                                         high = (high << 4) | low;
2667 -                                       
2668 -                                       /* map control-characters out */        
2669 +
2670 +                                       /* map out control characters */
2671                                         if (high < 32 || high == 127) high = '_';
2672 -                                       
2673 +
2674                                         *dst = high;
2675                                         src += 2;
2676                                 }
2677 @@ -891,7 +959,7 @@
2678   * /abc/./xyz       gets  /abc/xyz
2679   * /abc//xyz        gets  /abc/xyz
2680   *
2681 - * NOTE: src and dest can point to the same buffer, in which case,
2682 + * NOTE: src and dest can point to the same buffer, in which case
2683   *       the operation is performed in-place.
2684   */
2685  
2686 @@ -979,7 +1047,7 @@
2687  
2688  int light_isxdigit(int c) {
2689         if (light_isdigit(c)) return 1;
2690 -       
2691 +
2692         c |= 32;
2693         return (c >= 'a' && c <= 'f');
2694  }
2695 @@ -993,31 +1061,56 @@
2696         return light_isdigit(c) || light_isalpha(c);
2697  }
2698  
2699 +#undef BUFFER_CTYPE_FUNC
2700 +#define BUFFER_CTYPE_FUNC(type) \
2701 +       int buffer_is##type(buffer *b) { \
2702 +               size_t i, len; \
2703 +               if (b->used < 2) return 0; \
2704 +               /* strlen */ \
2705 +               len = b->used - 1; \
2706 +               /* c-string only */ \
2707 +               if (b->ptr[len] != '\0') { \
2708 +                       return 0; \
2709 +               } \
2710 +               /* check on the whole string */ \
2711 +               for (i = 0; i < len; i ++) { \
2712 +                       if (!light_is##type(b->ptr[i])) { \
2713 +                               return 0; \
2714 +                       } \
2715 +               } \
2716 +               return 1; \
2717 +       }
2718 +
2719 +BUFFER_CTYPE_FUNC(digit)
2720 +BUFFER_CTYPE_FUNC(xdigit)
2721 +BUFFER_CTYPE_FUNC(alpha)
2722 +BUFFER_CTYPE_FUNC(alnum)
2723 +
2724  int buffer_to_lower(buffer *b) {
2725         char *c;
2726 -       
2727 +
2728         if (b->used == 0) return 0;
2729 -       
2730 +
2731         for (c = b->ptr; *c; c++) {
2732                 if (*c >= 'A' && *c <= 'Z') {
2733                         *c |= 32;
2734                 }
2735         }
2736 -       
2737 +
2738         return 0;
2739  }
2740  
2741  
2742  int buffer_to_upper(buffer *b) {
2743         char *c;
2744 -       
2745 +
2746         if (b->used == 0) return 0;
2747 -       
2748 +
2749         for (c = b->ptr; *c; c++) {
2750                 if (*c >= 'a' && *c <= 'z') {
2751                         *c &= ~32;
2752                 }
2753         }
2754 -       
2755 +
2756         return 0;
2757  }
2758 --- ../lighttpd-1.4.11/src/buffer.h     2006-01-13 00:00:45.000000000 +0200
2759 +++ lighttpd-1.4.12/src/buffer.h        2006-07-18 13:03:40.000000000 +0300
2760 @@ -12,27 +12,43 @@
2761  
2762  typedef struct {
2763         char *ptr;
2764 -       
2765 +
2766         size_t used;
2767         size_t size;
2768  } buffer;
2769  
2770 +typedef void (*buffer_ptr_free_t)(void *p);
2771 +
2772 +typedef struct {
2773 +       void **ptr;
2774 +       size_t size;
2775 +       size_t used;
2776 +       buffer_ptr_free_t free;
2777 +} buffer_ptr;
2778 +
2779  typedef struct {
2780         buffer **ptr;
2781 -       
2782 +
2783         size_t used;
2784         size_t size;
2785  } buffer_array;
2786  
2787  typedef struct {
2788         char *ptr;
2789 -       
2790 -       size_t offset; /* input-pointer */
2791 -       
2792 -       size_t used;   /* output-pointer */
2793 +
2794 +       size_t offset; /* input pointer */
2795 +
2796 +       size_t used;   /* output pointer */
2797         size_t size;
2798  } read_buffer;
2799  
2800 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer);
2801 +void buffer_ptr_free(buffer_ptr *b);
2802 +void buffer_ptr_clear(buffer_ptr *b);
2803 +void buffer_ptr_append(buffer_ptr *b, void *item);
2804 +void *buffer_ptr_pop(buffer_ptr *b);
2805 +void *buffer_ptr_top(buffer_ptr *b);
2806 +
2807  buffer_array* buffer_array_init(void);
2808  void buffer_array_free(buffer_array *b);
2809  void buffer_array_reset(buffer_array *b);
2810 @@ -43,7 +59,7 @@
2811  buffer* buffer_init_string(const char *str);
2812  void buffer_free(buffer *b);
2813  void buffer_reset(buffer *b);
2814 -       
2815 +
2816  int buffer_prepare_copy(buffer *b, size_t size);
2817  int buffer_prepare_append(buffer *b, size_t size);
2818  
2819 @@ -85,9 +101,9 @@
2820  
2821  typedef enum {
2822         ENCODING_UNSET,
2823 -       ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of a href */
2824 -       ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus coding / too as %2F */
2825 -       ENCODING_HTML,    /* & becomes &amp; and so on */
2826 +       ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of an href */
2827 +       ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus encoding "/" as "%2F" */
2828 +       ENCODING_HTML,    /* "&" becomes "&amp;" and so on */
2829         ENCODING_MINIMAL_XML, /* minimal encoding for xml */
2830         ENCODING_HEX      /* encode string as hex */
2831  } buffer_encoding_t;
2832 @@ -111,20 +127,23 @@
2833  int light_isalpha(int c);
2834  int light_isalnum(int c);
2835  
2836 +#define BUFFER_CTYPE_FUNC(type) int buffer_is##type(buffer *b);
2837 +BUFFER_CTYPE_FUNC(digit)
2838 +BUFFER_CTYPE_FUNC(xdigit)
2839 +BUFFER_CTYPE_FUNC(alpha)
2840 +BUFFER_CTYPE_FUNC(alnum)
2841 +
2842 +#define BUF_STR(x) x->ptr
2843  #define BUFFER_APPEND_STRING_CONST(x, y) \
2844         buffer_append_string_len(x, y, sizeof(y) - 1)
2845  
2846  #define BUFFER_COPY_STRING_CONST(x, y) \
2847         buffer_copy_string_len(x, y, sizeof(y) - 1)
2848  
2849 -#define BUFFER_APPEND_SLASH(x) \
2850 -       if (x->used > 1 && x->ptr[x->used - 2] != '/') { BUFFER_APPEND_STRING_CONST(x, "/"); }
2851 -
2852  #define CONST_STR_LEN(x) x, x ? sizeof(x) - 1 : 0
2853 -#define CONST_BUF_LEN(x) x->ptr, x->used ? x->used - 1 : 0
2854 +#define CONST_BUF_LEN(x) BUF_STR(x), x->used ? x->used - 1 : 0
2855  
2856 -
2857 -#define SEGFAULT() do { fprintf(stderr, "%s.%d: aborted\n", __FILE__, __LINE__); abort(); } while(0)
2858 +       
2859  #define UNUSED(x) ( (void)(x) )
2860  
2861  #endif
2862 --- ../lighttpd-1.4.11/src/chunk.c      2005-11-18 15:18:19.000000000 +0200
2863 +++ lighttpd-1.4.12/src/chunk.c 2006-07-18 13:03:40.000000000 +0300
2864 @@ -1,16 +1,14 @@
2865  /**
2866   * the network chunk-API
2867 - * 
2868 - * 
2869 + *
2870 + *
2871   */
2872  
2873  #include <sys/types.h>
2874  #include <sys/stat.h>
2875 -#include <sys/mman.h>
2876  
2877  #include <stdlib.h>
2878  #include <fcntl.h>
2879 -#include <unistd.h>
2880  
2881  #include <stdio.h>
2882  #include <errno.h>
2883 @@ -18,36 +16,39 @@
2884  
2885  #include "chunk.h"
2886  
2887 +#include "sys-mmap.h"
2888 +#include "sys-files.h"
2889 +
2890  chunkqueue *chunkqueue_init(void) {
2891         chunkqueue *cq;
2892 -       
2893 +
2894         cq = calloc(1, sizeof(*cq));
2895 -       
2896 +
2897         cq->first = NULL;
2898         cq->last = NULL;
2899 -       
2900 +
2901         cq->unused = NULL;
2902 -       
2903 +
2904         return cq;
2905  }
2906  
2907  static chunk *chunk_init(void) {
2908         chunk *c;
2909 -       
2910 +
2911         c = calloc(1, sizeof(*c));
2912 -       
2913 +
2914         c->mem = buffer_init();
2915         c->file.name = buffer_init();
2916         c->file.fd = -1;
2917         c->file.mmap.start = MAP_FAILED;
2918         c->next = NULL;
2919 -       
2920 +
2921         return c;
2922  }
2923  
2924  static void chunk_free(chunk *c) {
2925         if (!c) return;
2926 -       
2927 +
2928         buffer_free(c->mem);
2929         buffer_free(c->file.name);
2930  
2931 @@ -56,13 +57,13 @@
2932  
2933  static void chunk_reset(chunk *c) {
2934         if (!c) return;
2935 -       
2936 +
2937         buffer_reset(c->mem);
2938  
2939         if (c->file.is_temp && !buffer_is_empty(c->file.name)) {
2940                 unlink(c->file.name->ptr);
2941         }
2942 -       
2943 +
2944         buffer_reset(c->file.name);
2945  
2946         if (c->file.fd != -1) {
2947 @@ -78,28 +79,28 @@
2948  
2949  void chunkqueue_free(chunkqueue *cq) {
2950         chunk *c, *pc;
2951 -       
2952 +
2953         if (!cq) return;
2954 -       
2955 +
2956         for (c = cq->first; c; ) {
2957                 pc = c;
2958                 c = c->next;
2959                 chunk_free(pc);
2960         }
2961 -       
2962 +
2963         for (c = cq->unused; c; ) {
2964                 pc = c;
2965                 c = c->next;
2966                 chunk_free(pc);
2967         }
2968 -       
2969 +
2970         free(cq);
2971  }
2972  
2973  static chunk *chunkqueue_get_unused_chunk(chunkqueue *cq) {
2974         chunk *c;
2975 -       
2976 -       /* check if we have a unused chunk */
2977 +
2978 +       /* check if we have an unused chunk */
2979         if (!cq->unused) {
2980                 c = chunk_init();
2981         } else {
2982 @@ -109,18 +110,18 @@
2983                 c->next = NULL;
2984                 cq->unused_chunks--;
2985         }
2986 -       
2987 +
2988         return c;
2989  }
2990  
2991  static int chunkqueue_prepend_chunk(chunkqueue *cq, chunk *c) {
2992         c->next = cq->first;
2993         cq->first = c;
2994 -       
2995 +
2996         if (cq->last == NULL) {
2997                 cq->last = c;
2998         }
2999 -       
3000 +
3001         return 0;
3002  }
3003  
3004 @@ -129,19 +130,19 @@
3005                 cq->last->next = c;
3006         }
3007         cq->last = c;
3008 -       
3009 +
3010         if (cq->first == NULL) {
3011                 cq->first = c;
3012         }
3013 -       
3014 +
3015         return 0;
3016  }
3017  
3018  void chunkqueue_reset(chunkqueue *cq) {
3019         chunk *c;
3020         /* move everything to the unused queue */
3021 -       
3022 -       /* mark all read written */ 
3023 +
3024 +       /* mark all read written */
3025         for (c = cq->first; c; c = c->next) {
3026                 switch(c->type) {
3027                 case MEM_CHUNK:
3028 @@ -150,7 +151,7 @@
3029                 case FILE_CHUNK:
3030                         c->offset = c->file.length;
3031                         break;
3032 -               default: 
3033 +               default:
3034                         break;
3035                 }
3036         }
3037 @@ -162,93 +163,93 @@
3038  
3039  int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
3040         chunk *c;
3041 -       
3042 +
3043         if (len == 0) return 0;
3044 -       
3045 +
3046         c = chunkqueue_get_unused_chunk(cq);
3047 -       
3048 +
3049         c->type = FILE_CHUNK;
3050 -       
3051 +
3052         buffer_copy_string_buffer(c->file.name, fn);
3053         c->file.start = offset;
3054         c->file.length = len;
3055         c->offset = 0;
3056 -       
3057 +
3058         chunkqueue_append_chunk(cq, c);
3059 -       
3060 +
3061         return 0;
3062  }
3063  
3064  int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
3065         chunk *c;
3066 -       
3067 +
3068         if (mem->used == 0) return 0;
3069 -       
3070 +
3071         c = chunkqueue_get_unused_chunk(cq);
3072         c->type = MEM_CHUNK;
3073         c->offset = 0;
3074         buffer_copy_string_buffer(c->mem, mem);
3075 -       
3076 +
3077         chunkqueue_append_chunk(cq, c);
3078 -       
3079 +
3080         return 0;
3081  }
3082  
3083  int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
3084         chunk *c;
3085 -       
3086 +
3087         if (mem->used == 0) return 0;
3088 -       
3089 +
3090         c = chunkqueue_get_unused_chunk(cq);
3091         c->type = MEM_CHUNK;
3092         c->offset = 0;
3093         buffer_copy_string_buffer(c->mem, mem);
3094 -       
3095 +
3096         chunkqueue_prepend_chunk(cq, c);
3097 -       
3098 +
3099         return 0;
3100  }
3101  
3102  int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
3103         chunk *c;
3104 -       
3105 +
3106         if (len == 0) return 0;
3107 -       
3108 +
3109         c = chunkqueue_get_unused_chunk(cq);
3110         c->type = MEM_CHUNK;
3111         c->offset = 0;
3112         buffer_copy_string_len(c->mem, mem, len - 1);
3113 -       
3114 +
3115         chunkqueue_append_chunk(cq, c);
3116 -       
3117 +
3118         return 0;
3119  }
3120  
3121  buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
3122         chunk *c;
3123 -       
3124 +
3125         c = chunkqueue_get_unused_chunk(cq);
3126 -       
3127 +
3128         c->type = MEM_CHUNK;
3129         c->offset = 0;
3130         buffer_reset(c->mem);
3131 -       
3132 +
3133         chunkqueue_prepend_chunk(cq, c);
3134 -       
3135 +
3136         return c->mem;
3137  }
3138  
3139  buffer *chunkqueue_get_append_buffer(chunkqueue *cq) {
3140         chunk *c;
3141 -       
3142 +
3143         c = chunkqueue_get_unused_chunk(cq);
3144 -       
3145 +
3146         c->type = MEM_CHUNK;
3147         c->offset = 0;
3148         buffer_reset(c->mem);
3149 -       
3150 +
3151         chunkqueue_append_chunk(cq, c);
3152 -       
3153 +
3154         return c->mem;
3155  }
3156  
3157 @@ -263,7 +264,7 @@
3158  chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
3159         chunk *c;
3160         buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX");
3161 -       
3162 +
3163         c = chunkqueue_get_unused_chunk(cq);
3164  
3165         c->type = FILE_CHUNK;
3166 @@ -273,12 +274,12 @@
3167                 size_t i;
3168  
3169                 /* we have several tempdirs, only if all of them fail we jump out */
3170 -               
3171 +
3172                 for (i = 0; i < cq->tempdirs->used; i++) {
3173                         data_string *ds = (data_string *)cq->tempdirs->data[i];
3174  
3175                         buffer_copy_string_buffer(template, ds->value);
3176 -                       BUFFER_APPEND_SLASH(template);
3177 +                       PATHNAME_APPEND_SLASH(template);
3178                         BUFFER_APPEND_STRING_CONST(template, "lighttpd-upload-XXXXXX");
3179  
3180                         if (-1 != (c->file.fd = mkstemp(template->ptr))) {
3181 @@ -300,7 +301,7 @@
3182         chunkqueue_append_chunk(cq, c);
3183  
3184         buffer_free(template);
3185 -       
3186 +
3187         return c;
3188  }
3189  
3190 @@ -308,7 +309,7 @@
3191  off_t chunkqueue_length(chunkqueue *cq) {
3192         off_t len = 0;
3193         chunk *c;
3194 -       
3195 +
3196         for (c = cq->first; c; c = c->next) {
3197                 switch (c->type) {
3198                 case MEM_CHUNK:
3199 @@ -321,14 +322,14 @@
3200                         break;
3201                 }
3202         }
3203 -       
3204 +
3205         return len;
3206  }
3207  
3208  off_t chunkqueue_written(chunkqueue *cq) {
3209         off_t len = 0;
3210         chunk *c;
3211 -       
3212 +
3213         for (c = cq->first; c; c = c->next) {
3214                 switch (c->type) {
3215                 case MEM_CHUNK:
3216 @@ -339,7 +340,7 @@
3217                         break;
3218                 }
3219         }
3220 -       
3221 +
3222         return len;
3223  }
3224  
3225 @@ -355,12 +356,13 @@
3226  
3227                 switch (c->type) {
3228                 case MEM_CHUNK:
3229 +                       if (c->mem->used == 0) is_finished = 1;
3230                         if (c->offset == (off_t)c->mem->used - 1) is_finished = 1;
3231                         break;
3232                 case FILE_CHUNK:
3233 -                       if (c->offset == c->file.length) is_finished = 1; 
3234 +                       if (c->offset == c->file.length) is_finished = 1;
3235                         break;
3236 -               default: 
3237 +               default:
3238                         break;
3239                 }
3240  
3241 @@ -383,3 +385,50 @@
3242  
3243         return 0;
3244  }
3245 +
3246 +void chunkqueue_print(chunkqueue *cq) {
3247 +       chunk *c;
3248 +
3249 +       for (c = cq->first; c; c = c->next) {
3250 +               fprintf(stderr, "(mem) %s", c->mem->ptr + c->offset);
3251 +       }
3252 +       fprintf(stderr, "\r\n");
3253 +}
3254 +
3255 +
3256 +/**
3257 + * remove the last chunk if it is empty
3258 + */
3259 +
3260 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq) {
3261 +       chunk *c;
3262 +       if (!cq->last) return;
3263 +       if (!cq->first) return;
3264 +
3265 +       if (cq->first == cq->last) {
3266 +               c = cq->first;
3267 +
3268 +               if (c->type != MEM_CHUNK) return;
3269 +               if (c->mem->used == 0) {
3270 +                       chunk_free(c);
3271 +                       cq->first = cq->last = NULL;
3272 +               }
3273 +               return;
3274 +       }
3275 +
3276 +       for (c = cq->first; c->next; c = c->next) {
3277 +               if (c->type != MEM_CHUNK) continue;
3278 +               if (c->mem->used != 0) continue;
3279 +
3280 +               if (c->next == cq->last) {
3281 +                       cq->last = c;
3282 +
3283 +                       chunk_free(c->next);
3284 +                       c->next = NULL;
3285 +
3286 +                       return;
3287 +               }
3288 +       }
3289 +}
3290 +
3291 +
3292 --- ../lighttpd-1.4.11/src/chunk.h      2005-11-01 09:32:21.000000000 +0200
3293 +++ lighttpd-1.4.12/src/chunk.h 2006-07-18 13:03:40.000000000 +0300
3294 @@ -6,7 +6,7 @@
3295  
3296  typedef struct chunk {
3297         enum { UNUSED_CHUNK, MEM_CHUNK, FILE_CHUNK } type;
3298 -       
3299 +
3300         buffer *mem; /* either the storage of the mem-chunk or the read-ahead buffer */
3301  
3302         struct {
3303 @@ -16,28 +16,28 @@
3304                 off_t  length; /* octets to send from the starting offset */
3305  
3306                 int    fd;
3307 -               struct { 
3308 +               struct {
3309                         char   *start; /* the start pointer of the mmap'ed area */
3310                         size_t length; /* size of the mmap'ed area */
3311 -                       off_t  offset; /* start is <n> octet away from the start of the file */
3312 +                       off_t  offset; /* start is <n> octets away from the start of the file */
3313                 } mmap;
3314  
3315 -               int is_temp; /* file is temporary and will be deleted if on cleanup */
3316 +               int is_temp; /* file is temporary and will be deleted on cleanup */
3317         } file;
3318 -       
3319 -       off_t  offset; /* octets sent from this chunk 
3320 -                         the size of the chunk is either 
3321 +
3322 +       off_t  offset; /* octets sent from this chunk
3323 +                         the size of the chunk is either
3324                           - mem-chunk: mem->used - 1
3325                           - file-chunk: file.length
3326                         */
3327 -       
3328 +
3329         struct chunk *next;
3330  } chunk;
3331  
3332  typedef struct {
3333         chunk *first;
3334         chunk *last;
3335 -       
3336 +
3337         chunk *unused;
3338         size_t unused_chunks;
3339  
3340 @@ -56,6 +56,7 @@
3341  buffer * chunkqueue_get_append_buffer(chunkqueue *c);
3342  buffer * chunkqueue_get_prepend_buffer(chunkqueue *c);
3343  chunk * chunkqueue_get_append_tempfile(chunkqueue *cq);
3344 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq);
3345  
3346  int chunkqueue_remove_finished_chunks(chunkqueue *cq);
3347  
3348 @@ -66,4 +67,6 @@
3349  
3350  int chunkqueue_is_empty(chunkqueue *c);
3351  
3352 +void chunkqueue_print(chunkqueue *cq);
3353 +
3354  #endif
3355 --- ../lighttpd-1.4.11/src/configfile-glue.c    2006-03-03 20:14:56.000000000 +0200
3356 +++ lighttpd-1.4.12/src/configfile-glue.c       2006-07-16 00:26:03.000000000 +0300
3357 @@ -1,4 +1,5 @@
3358  #include <string.h>
3359 +#include <ctype.h>
3360  
3361  #include "base.h"
3362  #include "buffer.h"
3363 @@ -11,10 +12,10 @@
3364   * are the external interface of lighttpd. The functions
3365   * are used by the server itself and the plugins.
3366   *
3367 - * The main-goal is to have a small library in the end 
3368 - * which is linked against both and which will define 
3369 + * The main-goal is to have a small library in the end
3370 + * which is linked against both and which will define
3371   * the interface itself in the end.
3372 - * 
3373 + *
3374   */
3375  
3376  
3377 @@ -24,56 +25,60 @@
3378  int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[]) {
3379         size_t i;
3380         data_unset *du;
3381 -       
3382 +
3383         for (i = 0; cv[i].key; i++) {
3384 -               
3385 +
3386                 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3387                         /* no found */
3388 -                       
3389 +
3390                         continue;
3391                 }
3392 -               
3393 +
3394                 switch (cv[i].type) {
3395                 case T_CONFIG_ARRAY:
3396                         if (du->type == TYPE_ARRAY) {
3397                                 size_t j;
3398                                 data_array *da = (data_array *)du;
3399 -                               
3400 +
3401                                 for (j = 0; j < da->value->used; j++) {
3402                                         if (da->value->data[j]->type == TYPE_STRING) {
3403                                                 data_string *ds = data_string_init();
3404 -                                               
3405 +
3406                                                 buffer_copy_string_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
3407                                                 if (!da->is_index_key) {
3408                                                         /* the id's were generated automaticly, as we copy now we might have to renumber them
3409 -                                                        * this is used to prepend server.modules by mod_indexfiles as it has to be loaded 
3410 +                                                        * this is used to prepend server.modules by mod_indexfiles as it has to be loaded
3411                                                          * before mod_fastcgi and friends */
3412                                                         buffer_copy_string_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
3413                                                 }
3414 -                                               
3415 +
3416                                                 array_insert_unique(cv[i].destination, (data_unset *)ds);
3417                                         } else {
3418 -                                               log_error_write(srv, __FILE__, __LINE__, "sssd", 
3419 -                                                               "the key of and array can only be a string or a integer, variable:", 
3420 -                                                               cv[i].key, "type:", da->value->data[j]->type); 
3421 -                                               
3422 +                                               log_error_write(srv, __FILE__, __LINE__, "sssd",
3423 +                                                               "the key of and array can only be a string or a integer, variable:",
3424 +                                                               cv[i].key, "type:", da->value->data[j]->type);
3425 +
3426                                                 return -1;
3427                                         }
3428                                 }
3429                         } else {
3430                                 log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", cv[i].key, "array of strings");
3431 -                               
3432 +
3433                                 return -1;
3434                         }
3435                         break;
3436                 case T_CONFIG_STRING:
3437                         if (du->type == TYPE_STRING) {
3438                                 data_string *ds = (data_string *)du;
3439 -                               
3440 +
3441                                 buffer_copy_string_buffer(cv[i].destination, ds->value);
3442 +                       } else if (du->type == TYPE_INTEGER) {
3443 +                               data_integer *di = (data_integer *)du;
3444 +
3445 +                               buffer_copy_long(cv[i].destination, di->value);
3446                         } else {
3447                                 log_error_write(srv, __FILE__, __LINE__, "ssss", "unexpected type for key: ", cv[i].key, "(string)", "\"...\"");
3448 -                               
3449 +
3450                                 return -1;
3451                         }
3452                         break;
3453 @@ -81,15 +86,20 @@
3454                         switch(du->type) {
3455                         case TYPE_INTEGER: {
3456                                 data_integer *di = (data_integer *)du;
3457 -                               
3458 +
3459                                 *((unsigned short *)(cv[i].destination)) = di->value;
3460                                 break;
3461                         }
3462                         case TYPE_STRING: {
3463                                 data_string *ds = (data_string *)du;
3464 -                                       
3465 +
3466 +                               if (buffer_isdigit(ds->value)) {
3467 +                                       *((unsigned short *)(cv[i].destination)) = strtol(ds->value->ptr, NULL, 10);
3468 +                                       break;
3469 +                               }
3470 +
3471                                 log_error_write(srv, __FILE__, __LINE__, "ssb", "get a string but expected a short:", cv[i].key, ds->value);
3472 -                               
3473 +
3474                                 return -1;
3475                         }
3476                         default:
3477 @@ -100,19 +110,19 @@
3478                 case T_CONFIG_BOOLEAN:
3479                         if (du->type == TYPE_STRING) {
3480                                 data_string *ds = (data_string *)du;
3481 -                               
3482 +
3483                                 if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
3484                                         *((unsigned short *)(cv[i].destination)) = 1;
3485                                 } else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
3486                                         *((unsigned short *)(cv[i].destination)) = 0;
3487                                 } else {
3488                                         log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
3489 -                                               
3490 +
3491                                         return -1;
3492                                 }
3493                         } else {
3494                                 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
3495 -                               
3496 +
3497                                 return -1;
3498                         }
3499                         break;
3500 @@ -121,9 +131,9 @@
3501                         break;
3502                 case T_CONFIG_DEPRECATED:
3503                         log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
3504 -                       
3505 +
3506                         srv->config_deprecated = 1;
3507 -                       
3508 +
3509                         break;
3510                 }
3511         }
3512 @@ -133,25 +143,25 @@
3513  int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
3514         size_t i;
3515         data_unset *du;
3516 -       
3517 +
3518         for (i = 0; cv[i].key; i++) {
3519                 data_string *touched;
3520 -               
3521 +
3522                 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3523                         /* no found */
3524 -                       
3525 +
3526                         continue;
3527                 }
3528 -               
3529 +
3530                 /* touched */
3531                 touched = data_string_init();
3532 -               
3533 +
3534                 buffer_copy_string(touched->value, "");
3535                 buffer_copy_string_buffer(touched->key, du->key);
3536 -               
3537 +
3538                 array_insert_unique(srv->config_touched, (data_unset *)touched);
3539         }
3540 -       
3541 +
3542         return config_insert_values_internal(srv, ca, cv);
3543  }
3544  
3545 @@ -191,25 +201,25 @@
3546         }
3547  
3548         /* pass the rules */
3549 -       
3550 +
3551         switch (dc->comp) {
3552         case COMP_HTTP_HOST: {
3553                 char *ck_colon = NULL, *val_colon = NULL;
3554 -               
3555 +
3556                 if (!buffer_is_empty(con->uri.authority)) {
3557 -               
3558 -                       /* 
3559 +
3560 +                       /*
3561                          * append server-port to the HTTP_POST if necessary
3562                          */
3563 -                       
3564 +
3565                         l = con->uri.authority;
3566 -                       
3567 +
3568                         switch(dc->cond) {
3569                         case CONFIG_COND_NE:
3570                         case CONFIG_COND_EQ:
3571                                 ck_colon = strchr(dc->string->ptr, ':');
3572                                 val_colon = strchr(l->ptr, ':');
3573 -                               
3574 +
3575                                 if (ck_colon == val_colon) {
3576                                         /* nothing to do with it */
3577                                         break;
3578 @@ -230,21 +240,21 @@
3579                                 break;
3580                         }
3581                 } else {
3582 -                       l = NULL;
3583 +                       l = srv->empty_string;
3584                 }
3585                 break;
3586         }
3587         case COMP_HTTP_REMOTEIP: {
3588                 char *nm_slash;
3589 -               /* handle remoteip limitations 
3590 -                * 
3591 +               /* handle remoteip limitations
3592 +                *
3593                  * "10.0.0.1" is provided for all comparisions
3594 -                * 
3595 +                *
3596                  * only for == and != we support
3597 -                * 
3598 +                *
3599                  * "10.0.0.1/24"
3600                  */
3601 -               
3602 +
3603                 if ((dc->cond == CONFIG_COND_EQ ||
3604                      dc->cond == CONFIG_COND_NE) &&
3605                     (con->dst_addr.plain.sa_family == AF_INET) &&
3606 @@ -253,41 +263,48 @@
3607                         long nm;
3608                         char *err;
3609                         struct in_addr val_inp;
3610 -                       
3611 +
3612 +                       if (con->conf.log_condition_handling) {
3613 +                               l = srv->empty_string;
3614 +
3615 +                               log_error_write(srv, __FILE__, __LINE__,  "bsbsb", dc->comp_key,
3616 +                                               "(", l, ") compare to", dc->string);
3617 +                       }
3618 +
3619                         if (*(nm_slash+1) == '\0') {
3620                                 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string);
3621 -                                       
3622 +
3623                                 return COND_RESULT_FALSE;
3624                         }
3625 -                       
3626 +
3627                         nm_bits = strtol(nm_slash + 1, &err, 10);
3628 -                       
3629 +
3630                         if (*err) {
3631                                 log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, *err);
3632 -                               
3633 +
3634                                 return COND_RESULT_FALSE;
3635                         }
3636 -                       
3637 +
3638                         /* take IP convert to the native */
3639                         buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr);
3640 -#ifdef __WIN32                 
3641 +#ifdef _WIN32
3642                         if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) {
3643                                 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3644 -                               
3645 +
3646                                 return COND_RESULT_FALSE;
3647                         }
3648  
3649  #else
3650                         if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) {
3651                                 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3652 -                               
3653 +
3654                                 return COND_RESULT_FALSE;
3655                         }
3656  #endif
3657 -                       
3658 +
3659                         /* build netmask */
3660                         nm = htonl(~((1 << (32 - nm_bits)) - 1));
3661 -                       
3662 +
3663                         if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) {
3664                                 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
3665                         } else {
3666 @@ -308,7 +325,7 @@
3667  
3668         case COMP_HTTP_REFERER: {
3669                 data_string *ds;
3670 -               
3671 +
3672                 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
3673                         l = ds->value;
3674                 } else {
3675 @@ -338,7 +355,7 @@
3676         default:
3677                 return COND_RESULT_FALSE;
3678         }
3679 -       
3680 +
3681         if (NULL == l) {
3682                 if (con->conf.log_condition_handling) {
3683                         log_error_write(srv, __FILE__, __LINE__,  "bsbs", dc->comp_key,
3684 @@ -346,10 +363,10 @@
3685                 }
3686                 return COND_RESULT_FALSE;
3687         }
3688 -       
3689 +
3690         if (con->conf.log_condition_handling) {
3691                 log_error_write(srv, __FILE__, __LINE__,  "bsbsb", dc->comp_key,
3692 -                               "(", l, ") compare to ", dc->string);
3693 +                               "(", l, ") compare to", dc->string);
3694         }
3695         switch(dc->cond) {
3696         case CONFIG_COND_NE:
3697 @@ -365,13 +382,13 @@
3698         case CONFIG_COND_MATCH: {
3699                 cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
3700                 int n;
3701 -               
3702 +
3703  #ifndef elementsof
3704  #define elementsof(x) (sizeof(x) / sizeof(x[0]))
3705  #endif
3706                 n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0,
3707                                 cache->matches, elementsof(cache->matches));
3708 -               
3709 +
3710                 cache->patterncount = n;
3711                 if (n > 0) {
3712                         cache->comp_value = l;
3713 @@ -387,7 +404,7 @@
3714                 /* no way */
3715                 break;
3716         }
3717 -       
3718 +
3719         return COND_RESULT_FALSE;
3720  }
3721  
3722 @@ -395,6 +412,9 @@
3723         cond_cache_t *caches = con->cond_cache;
3724  
3725         if (COND_RESULT_UNSET == caches[dc->context_ndx].result) {
3726 +               if (con->conf.log_condition_handling) {
3727 +                       log_error_write(srv, __FILE__, __LINE__,  "sds",  "=== start of", dc->context_ndx, "condition block ===");
3728 +               }
3729                 if (COND_RESULT_TRUE == (caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc))) {
3730                         if (dc->next) {
3731                                 data_config *c;
3732 @@ -409,11 +429,11 @@
3733                 }
3734                 if (con->conf.log_condition_handling) {
3735                         log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3736 -                                       "(uncached) result:",
3737 +                                       "result:",
3738                                         caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3739                 }
3740         } else {
3741 -               if (con->conf.log_condition_handling) {
3742 +               if (con->conf.log_condition_cache_handling) {
3743                         log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3744                                         "(cached) result:",
3745                                         caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3746 @@ -423,9 +443,6 @@
3747  }
3748  
3749  int config_check_cond(server *srv, connection *con, data_config *dc) {
3750 -       if (con->conf.log_condition_handling) {
3751 -               log_error_write(srv, __FILE__, __LINE__,  "s",  "=== start of condition block ===");
3752 -       }
3753         return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
3754  }
3755  
3756 @@ -443,3 +460,85 @@
3757         return 1;
3758  }
3759  
3760 +/* return <0 on error
3761 + * return 0-x if matched (and replaced)
3762 + */
3763 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result)
3764 +{
3765 +#ifdef HAVE_PCRE_H
3766 +       pcre *match;
3767 +       pcre_extra *extra;
3768 +       const char *pattern;
3769 +       size_t pattern_len;
3770 +       int n;
3771 +       size_t i;
3772 +       pcre_keyvalue *kv;
3773 +# define N 10
3774 +       int ovec[N * 3];
3775 +
3776 +       for (i = 0; i < kvb->used; i++) {
3777 +               kv = kvb->kv[i];
3778 +
3779 +               match       = kv->key;
3780 +               extra       = kv->key_extra;
3781 +               pattern     = kv->value->ptr;
3782 +               pattern_len = kv->value->used - 1;
3783 +
3784 +               if ((n = pcre_exec(match, extra, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
3785 +                       if (n != PCRE_ERROR_NOMATCH) {
3786 +                               return n;
3787 +                       }
3788 +               } else {
3789 +                       const char **list;
3790 +                       size_t start, end;
3791 +                       size_t k;
3792 +
3793 +                       /* it matched */
3794 +                       pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
3795 +
3796 +                       /* search for $[0-9] */
3797 +
3798 +                       buffer_reset(result);
3799 +
3800 +                       start = 0; end = pattern_len;
3801 +                       for (k = 0; k < pattern_len; k++) {
3802 +                               if ((pattern[k] == '$' || pattern[k] == '%') &&
3803 +                                   isdigit((unsigned char)pattern[k + 1])) {
3804 +                                       /* got one */
3805 +
3806 +                                       size_t num = pattern[k + 1] - '0';
3807 +
3808 +                                       end = k;
3809 +
3810 +                                       buffer_append_string_len(result, pattern + start, end - start);
3811 +
3812 +                                       if (pattern[k] == '$') {
3813 +                                               /* n is always > 0 */
3814 +                                               if (num < (size_t)n) {
3815 +                                                       buffer_append_string(result, list[num]);
3816 +                                               }
3817 +                                       } else {
3818 +                                               config_append_cond_match_buffer(con, context, result, num);
3819 +                                       }
3820 +
3821 +                                       k++;
3822 +                                       start = k + 1;
3823 +                               }
3824 +                       }
3825 +
3826 +                       buffer_append_string_len(result, pattern + start, pattern_len - start);
3827 +
3828 +                       pcre_free(list);
3829 +
3830 +                       return i;
3831 +               }
3832 +       }
3833 +
3834 +       return PCRE_ERROR_NOMATCH;
3835 +#undef N
3836 +#else
3837 +       UNUSED(kvb);
3838 +       return -2;
3839 +#endif
3840 +}
3841 +
3842 --- ../lighttpd-1.4.11/src/configfile.c 2006-02-15 14:26:42.000000000 +0200
3843 +++ lighttpd-1.4.12/src/configfile.c    2006-07-18 13:03:40.000000000 +0300
3844 @@ -2,7 +2,6 @@
3845  
3846  #include <stdlib.h>
3847  #include <fcntl.h>
3848 -#include <unistd.h>
3849  #include <errno.h>
3850  #include <string.h>
3851  #include <stdio.h>
3852 @@ -13,21 +12,24 @@
3853  #include "log.h"
3854  #include "stream.h"
3855  #include "plugin.h"
3856 -#ifdef USE_LICENSE
3857 -#include "license.h"
3858 -#endif
3859 -
3860  #include "configparser.h"
3861  #include "configfile.h"
3862  #include "proc_open.h"
3863  
3864 +#include "sys-files.h"
3865 +#include "sys-process.h"
3866 +
3867 +#ifndef PATH_MAX
3868 +/* win32 */
3869 +#define PATH_MAX 64
3870 +#endif
3871  
3872  static int config_insert(server *srv) {
3873         size_t i;
3874         int ret = 0;
3875         buffer *stat_cache_string;
3876 -       
3877 -       config_values_t cv[] = { 
3878 +
3879 +       config_values_t cv[] = {
3880                 { "server.bind",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 0 */
3881                 { "server.errorlog",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 1 */
3882                 { "server.errorfile-prefix",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 2 */
3883 @@ -38,7 +40,7 @@
3884                 { "server.tag",                  NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 7 */
3885                 { "server.use-ipv6",             NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
3886                 { "server.modules",              NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER },       /* 9 */
3887 -               
3888 +
3889                 { "server.event-handler",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 10 */
3890                 { "server.pid-file",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 11 */
3891                 { "server.max-request-size",     NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 12 */
3892 @@ -49,7 +51,7 @@
3893                 { "server.max-keep-alive-requests", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
3894                 { "server.name",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 18 */
3895                 { "server.max-keep-alive-idle",  NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 19 */
3896 -               
3897 +
3898                 { "server.max-read-idle",        NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 20 */
3899                 { "server.max-write-idle",       NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 21 */
3900                 { "server.error-handler-404",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 22 */
3901 @@ -60,19 +62,19 @@
3902                 { "mimetype.use-xattr",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 27 */
3903                 { "mimetype.assign",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },   /* 28 */
3904                 { "ssl.pemfile",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 29 */
3905 -               
3906 +
3907                 { "ssl.engine",                  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 30 */
3908 -               
3909 +
3910                 { "debug.log-file-not-found",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 31 */
3911                 { "debug.log-request-handling",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 32 */
3912                 { "debug.log-response-header",   NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 33 */
3913                 { "debug.log-request-header",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 34 */
3914 -               
3915 +
3916                 { "server.protocol-http11",      NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 35 */
3917                 { "debug.log-request-header-on-error", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 36 */
3918                 { "debug.log-state-handling",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 37 */
3919                 { "ssl.ca-file",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 38 */
3920 -               
3921 +
3922                 { "server.errorlog-use-syslog",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 39 */
3923                 { "server.range-requests",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 40 */
3924                 { "server.stat-cache-engine",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 41 */
3925 @@ -80,7 +82,8 @@
3926                 { "server.network-backend",      NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 43 */
3927                 { "server.upload-dirs",          NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },   /* 44 */
3928                 { "server.core-files",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 45 */
3929 -               
3930 +               { "debug.log-condition-cache-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },    /* 46 */
3931 +
3932                 { "server.host",                 "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3933                 { "server.docroot",              "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3934                 { "server.virtual-root",         "load mod_simple_vhost and use simple-vhost.server-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3935 @@ -90,11 +93,11 @@
3936                 { "server.groupid",              "use server.groupname instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3937                 { "server.use-keep-alive",       "use server.max-keep-alive-requests = 0 instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3938                 { "server.force-lower-case-files",       "use server.force-lowercase-filenames instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3939 -               
3940 +
3941                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
3942         };
3943  
3944 -       
3945 +
3946         /* 0 */
3947         cv[0].destination = srv->srvconf.bindhost;
3948         cv[1].destination = srv->srvconf.errorlog_file;
3949 @@ -102,33 +105,33 @@
3950         cv[4].destination = srv->srvconf.username;
3951         cv[5].destination = srv->srvconf.groupname;
3952         cv[6].destination = &(srv->srvconf.port);
3953 -       
3954 +
3955         cv[9].destination = srv->srvconf.modules;
3956         cv[10].destination = srv->srvconf.event_handler;
3957         cv[11].destination = srv->srvconf.pid_file;
3958 -       
3959 +
3960         cv[13].destination = &(srv->srvconf.max_worker);
3961         cv[23].destination = &(srv->srvconf.max_fds);
3962         cv[36].destination = &(srv->srvconf.log_request_header_on_error);
3963         cv[37].destination = &(srv->srvconf.log_state_handling);
3964 -       
3965 +
3966         cv[39].destination = &(srv->srvconf.errorlog_use_syslog);
3967 -       
3968 +
3969         stat_cache_string = buffer_init();
3970         cv[41].destination = stat_cache_string;
3971         cv[43].destination = srv->srvconf.network_backend;
3972         cv[44].destination = srv->srvconf.upload_tempdirs;
3973         cv[45].destination = &(srv->srvconf.enable_cores);
3974 -       
3975 +
3976         cv[42].destination = &(srv->srvconf.max_conns);
3977         cv[12].destination = &(srv->srvconf.max_request_size);
3978         srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
3979  
3980         assert(srv->config_storage);
3981 -       
3982 +
3983         for (i = 0; i < srv->config_context->used; i++) {
3984                 specific_config *s;
3985 -               
3986 +
3987                 s = calloc(1, sizeof(specific_config));
3988                 assert(s);
3989                 s->document_root = buffer_init();
3990 @@ -154,17 +157,18 @@
3991                 s->global_kbytes_per_second = 0;
3992                 s->global_bytes_per_second_cnt = 0;
3993                 s->global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
3994 -               
3995 +
3996                 cv[2].destination = s->errorfile_prefix;
3997 -               
3998 +
3999                 cv[7].destination = s->server_tag;
4000                 cv[8].destination = &(s->use_ipv6);
4001 -               
4002 -               
4003 +
4004 +
4005                 /* 13 max-worker */
4006                 cv[14].destination = s->document_root;
4007                 cv[15].destination = &(s->force_lowercase_filenames);
4008                 cv[16].destination = &(s->log_condition_handling);
4009 +               cv[46].destination = &(s->log_condition_cache_handling);
4010                 cv[17].destination = &(s->max_keep_alive_requests);
4011                 cv[18].destination = s->server_name;
4012                 cv[19].destination = &(s->max_keep_alive_idle);
4013 @@ -179,23 +183,23 @@
4014                 cv[28].destination = s->mimetypes;
4015                 cv[29].destination = s->ssl_pemfile;
4016                 cv[30].destination = &(s->is_ssl);
4017 -               
4018 +
4019                 cv[31].destination = &(s->log_file_not_found);
4020                 cv[32].destination = &(s->log_request_handling);
4021                 cv[33].destination = &(s->log_response_header);
4022                 cv[34].destination = &(s->log_request_header);
4023 -               
4024 +
4025                 cv[35].destination = &(s->allow_http11);
4026                 cv[38].destination = s->ssl_ca_file;
4027                 cv[40].destination = &(s->range_requests);
4028 -               
4029 +
4030                 srv->config_storage[i] = s;
4031 -       
4032 +
4033                 if (0 != (ret = config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv))) {
4034                         break;
4035                 }
4036         }
4037 -       
4038 +
4039         if (buffer_is_empty(stat_cache_string)) {
4040                 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
4041         } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) {
4042 @@ -205,22 +209,22 @@
4043         } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("disable"))) {
4044                 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE;
4045         } else {
4046 -               log_error_write(srv, __FILE__, __LINE__, "sb", 
4047 +               log_error_write(srv, __FILE__, __LINE__, "sb",
4048                                 "server.stat-cache-engine can be one of \"disable\", \"simple\", \"fam\", but not:", stat_cache_string);
4049                 ret = HANDLER_ERROR;
4050         }
4051 -       
4052 +
4053         buffer_free(stat_cache_string);
4054 -       
4055 +
4056         return ret;
4057 -                                                                
4058 -}
4059  
4060 +}
4061  
4062 -#define PATCH(x) con->conf.x = s->x
4063 +#define PATCH(x) \
4064 +       con->conf.x = s->x
4065  int config_setup_connection(server *srv, connection *con) {
4066         specific_config *s = srv->config_storage[0];
4067 -       
4068 +
4069         PATCH(allow_http11);
4070         PATCH(mimetypes);
4071         PATCH(document_root);
4072 @@ -236,20 +240,21 @@
4073         PATCH(kbytes_per_second);
4074         PATCH(global_kbytes_per_second);
4075         PATCH(global_bytes_per_second_cnt);
4076 -       
4077 +
4078         con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
4079         buffer_copy_string_buffer(con->server_name, s->server_name);
4080 -       
4081 +
4082         PATCH(log_request_header);
4083         PATCH(log_response_header);
4084         PATCH(log_request_handling);
4085         PATCH(log_condition_handling);
4086 +       PATCH(log_condition_cache_handling);
4087         PATCH(log_file_not_found);
4088 -       
4089 +
4090         PATCH(range_requests);
4091         PATCH(force_lowercase_filenames);
4092         PATCH(is_ssl);
4093 -       
4094 +
4095         PATCH(ssl_pemfile);
4096         PATCH(ssl_ca_file);
4097         return 0;
4098 @@ -257,22 +262,22 @@
4099  
4100  int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
4101         size_t i, j;
4102 -       
4103 +
4104         /* skip the first, the global context */
4105         for (i = 1; i < srv->config_context->used; i++) {
4106                 data_config *dc = (data_config *)srv->config_context->data[i];
4107                 specific_config *s = srv->config_storage[i];
4108 -               
4109 +
4110                 /* not our stage */
4111                 if (comp != dc->comp) continue;
4112 -               
4113 +
4114                 /* condition didn't match */
4115                 if (!config_check_cond(srv, con, dc)) continue;
4116 -               
4117 +
4118                 /* merge config */
4119                 for (j = 0; j < dc->value->used; j++) {
4120                         data_unset *du = dc->value->data[j];
4121 -                       
4122 +
4123                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.document-root"))) {
4124                                 PATCH(document_root);
4125                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.range-requests"))) {
4126 @@ -315,11 +320,13 @@
4127                                 PATCH(log_response_header);
4128                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-handling"))) {
4129                                 PATCH(log_condition_handling);
4130 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-cache-handling"))) {
4131 +                               PATCH(log_condition_cache_handling);
4132                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-file-not-found"))) {
4133                                 PATCH(log_file_not_found);
4134                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
4135                                 PATCH(allow_http11);
4136 -                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {  
4137 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
4138                                 PATCH(force_lowercase_filenames);
4139                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
4140                                 PATCH(global_kbytes_per_second);
4141 @@ -328,7 +335,7 @@
4142                         }
4143                 }
4144         }
4145 -       
4146 +
4147         return 0;
4148  }
4149  #undef PATCH
4150 @@ -336,15 +343,15 @@
4151  typedef struct {
4152         int foo;
4153         int bar;
4154 -       
4155 +
4156         const buffer *source;
4157         const char *input;
4158         size_t offset;
4159         size_t size;
4160 -       
4161 +
4162         int line_pos;
4163         int line;
4164 -       
4165 +
4166         int in_key;
4167         int in_brace;
4168         int in_cond;
4169 @@ -362,7 +369,7 @@
4170         }
4171  
4172         if (0 != stream_open(&(t->s), t->file)) {
4173 -               log_error_write(srv, __FILE__, __LINE__, "sbss", 
4174 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
4175                                 "opening configfile ", t->file, "failed:", strerror(errno));
4176                 buffer_free(t->file);
4177                 return -1;
4178 @@ -373,7 +380,7 @@
4179         t->size = t->s.size;
4180         t->line = 1;
4181         t->line_pos = 1;
4182 -       
4183 +
4184         t->in_key = 1;
4185         t->in_brace = 0;
4186         t->in_cond = 0;
4187 @@ -401,7 +408,7 @@
4188  static int config_skip_comment(tokenizer_t *t) {
4189         int i;
4190         assert(t->input[t->offset] == '#');
4191 -       for (i = 1; t->input[t->offset + i] && 
4192 +       for (i = 1; t->input[t->offset + i] &&
4193              (t->input[t->offset + i] != '\n' && t->input[t->offset + i] != '\r');
4194              i++);
4195         t->offset += i;
4196 @@ -411,44 +418,44 @@
4197  static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *token) {
4198         int tid = 0;
4199         size_t i;
4200 -       
4201 +
4202         for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
4203                 char c = t->input[t->offset];
4204                 const char *start = NULL;
4205 -               
4206 +
4207                 switch (c) {
4208 -               case '=': 
4209 +               case '=':
4210                         if (t->in_brace) {
4211                                 if (t->input[t->offset + 1] == '>') {
4212                                         t->offset += 2;
4213 -                                       
4214 +
4215                                         buffer_copy_string(token, "=>");
4216 -                                       
4217 +
4218                                         tid = TK_ARRAY_ASSIGN;
4219                                 } else {
4220 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4221 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4222                                                         "source:", t->source,
4223 -                                                       "line:", t->line, "pos:", t->line_pos, 
4224 +                                                       "line:", t->line, "pos:", t->line_pos,
4225                                                         "use => for assignments in arrays");
4226                                         return -1;
4227                                 }
4228                         } else if (t->in_cond) {
4229                                 if (t->input[t->offset + 1] == '=') {
4230                                         t->offset += 2;
4231 -                                       
4232 +
4233                                         buffer_copy_string(token, "==");
4234 -                                       
4235 +
4236                                         tid = TK_EQ;
4237                                 } else if (t->input[t->offset + 1] == '~') {
4238                                         t->offset += 2;
4239 -                                       
4240 +
4241                                         buffer_copy_string(token, "=~");
4242 -                                       
4243 +
4244                                         tid = TK_MATCH;
4245                                 } else {
4246 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4247 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4248                                                         "source:", t->source,
4249 -                                                       "line:", t->line, "pos:", t->line_pos, 
4250 +                                                       "line:", t->line, "pos:", t->line_pos,
4251                                                         "only =~ and == are allowed in the condition");
4252                                         return -1;
4253                                 }
4254 @@ -456,51 +463,51 @@
4255                                 t->in_cond = 0;
4256                         } else if (t->in_key) {
4257                                 tid = TK_ASSIGN;
4258 -                               
4259 +
4260                                 buffer_copy_string_len(token, t->input + t->offset, 1);
4261 -                               
4262 +
4263                                 t->offset++;
4264                                 t->line_pos++;
4265                         } else {
4266 -                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4267 +                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4268                                                 "source:", t->source,
4269 -                                               "line:", t->line, "pos:", t->line_pos, 
4270 +                                               "line:", t->line, "pos:", t->line_pos,
4271                                                 "unexpected equal-sign: =");
4272                                 return -1;
4273                         }
4274 -                       
4275 +
4276                         break;
4277 -               case '!': 
4278 +               case '!':
4279                         if (t->in_cond) {
4280                                 if (t->input[t->offset + 1] == '=') {
4281                                         t->offset += 2;
4282 -                                       
4283 +
4284                                         buffer_copy_string(token, "!=");
4285 -                                       
4286 +
4287                                         tid = TK_NE;
4288                                 } else if (t->input[t->offset + 1] == '~') {
4289                                         t->offset += 2;
4290 -                                       
4291 +
4292                                         buffer_copy_string(token, "!~");
4293 -                                       
4294 +
4295                                         tid = TK_NOMATCH;
4296                                 } else {
4297 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4298 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4299                                                         "source:", t->source,
4300 -                                                       "line:", t->line, "pos:", t->line_pos, 
4301 +                                                       "line:", t->line, "pos:", t->line_pos,
4302                                                         "only !~ and != are allowed in the condition");
4303                                         return -1;
4304                                 }
4305                                 t->in_key = 1;
4306                                 t->in_cond = 0;
4307                         } else {
4308 -                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4309 +                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4310                                                 "source:", t->source,
4311 -                                               "line:", t->line, "pos:", t->line_pos, 
4312 +                                               "line:", t->line, "pos:", t->line_pos,
4313                                                 "unexpected exclamation-marks: !");
4314                                 return -1;
4315                         }
4316 -                       
4317 +
4318                         break;
4319                 case '\t':
4320                 case ' ':
4321 @@ -546,10 +553,10 @@
4322                 case ',':
4323                         if (t->in_brace > 0) {
4324                                 tid = TK_COMMA;
4325 -                               
4326 +
4327                                 buffer_copy_string(token, "(COMMA)");
4328                         }
4329 -                       
4330 +
4331                         t->offset++;
4332                         t->line_pos++;
4333                         break;
4334 @@ -557,70 +564,70 @@
4335                         /* search for the terminating " */
4336                         start = t->input + t->offset + 1;
4337                         buffer_copy_string(token, "");
4338 -                       
4339 +
4340                         for (i = 1; t->input[t->offset + i]; i++) {
4341                                 if (t->input[t->offset + i] == '\\' &&
4342                                     t->input[t->offset + i + 1] == '"') {
4343 -                                       
4344 +
4345                                         buffer_append_string_len(token, start, t->input + t->offset + i - start);
4346 -                                       
4347 +
4348                                         start = t->input + t->offset + i + 1;
4349 -                                       
4350 +
4351                                         /* skip the " */
4352                                         i++;
4353                                         continue;
4354                                 }
4355 -                               
4356 -                               
4357 +
4358 +
4359                                 if (t->input[t->offset + i] == '"') {
4360                                         tid = TK_STRING;
4361 -                               
4362 +
4363                                         buffer_append_string_len(token, start, t->input + t->offset + i - start);
4364 -                                       
4365 +
4366                                         break;
4367                                 }
4368                         }
4369  
4370                         if (t->input[t->offset + i] == '\0') {
4371                                 /* ERROR */
4372 -                               
4373 -                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4374 +
4375 +                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4376                                                 "source:", t->source,
4377 -                                               "line:", t->line, "pos:", t->line_pos, 
4378 +                                               "line:", t->line, "pos:", t->line_pos,
4379                                                 "missing closing quote");
4380 -                               
4381 +
4382                                 return -1;
4383                         }
4384 -                       
4385 +
4386                         t->offset += i + 1;
4387                         t->line_pos += i + 1;
4388 -                       
4389 +
4390                         break;
4391                 case '(':
4392                         t->offset++;
4393                         t->in_brace++;
4394 -                               
4395 +
4396                         tid = TK_LPARAN;
4397 -                               
4398 +
4399                         buffer_copy_string(token, "(");
4400                         break;
4401                 case ')':
4402                         t->offset++;
4403                         t->in_brace--;
4404 -                               
4405 +
4406                         tid = TK_RPARAN;
4407 -                               
4408 +
4409                         buffer_copy_string(token, ")");
4410                         break;
4411                 case '$':
4412                         t->offset++;
4413 -                               
4414 +
4415                         tid = TK_DOLLAR;
4416                         t->in_cond = 1;
4417                         t->in_key = 0;
4418 -                               
4419 +
4420                         buffer_copy_string(token, "$");
4421 -                       
4422 +
4423                         break;
4424  
4425                 case '+':
4426 @@ -637,115 +644,107 @@
4427  
4428                 case '{':
4429                         t->offset++;
4430 -                               
4431 +
4432                         tid = TK_LCURLY;
4433 -                               
4434 +
4435                         buffer_copy_string(token, "{");
4436 -                       
4437 +
4438                         break;
4439 -                       
4440 +
4441                 case '}':
4442                         t->offset++;
4443 -                               
4444 +
4445                         tid = TK_RCURLY;
4446 -                               
4447 +
4448                         buffer_copy_string(token, "}");
4449 -                       
4450 +
4451                         break;
4452  
4453                 case '[':
4454                         t->offset++;
4455 -                               
4456 +
4457                         tid = TK_LBRACKET;
4458 -                               
4459 +
4460                         buffer_copy_string(token, "[");
4461 -                       
4462 +
4463                         break;
4464 -                       
4465 +
4466                 case ']':
4467                         t->offset++;
4468 -                               
4469 +
4470                         tid = TK_RBRACKET;
4471 -                               
4472 +
4473                         buffer_copy_string(token, "]");
4474 -                       
4475 +
4476                         break;
4477                 case '#':
4478                         t->line_pos += config_skip_comment(t);
4479 -                       
4480 +
4481                         break;
4482                 default:
4483                         if (t->in_cond) {
4484 -                               for (i = 0; t->input[t->offset + i] && 
4485 +                               for (i = 0; t->input[t->offset + i] &&
4486                                      (isalpha((unsigned char)t->input[t->offset + i])
4487                                       ); i++);
4488 -                               
4489 +
4490                                 if (i && t->input[t->offset + i]) {
4491                                         tid = TK_SRVVARNAME;
4492                                         buffer_copy_string_len(token, t->input + t->offset, i);
4493 -                                       
4494 +
4495                                         t->offset += i;
4496                                         t->line_pos += i;
4497                                 } else {
4498                                         /* ERROR */
4499 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4500 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4501                                                         "source:", t->source,
4502 -                                                       "line:", t->line, "pos:", t->line_pos, 
4503 +                                                       "line:", t->line, "pos:", t->line_pos,
4504                                                         "invalid character in condition");
4505                                         return -1;
4506                                 }
4507                         } else if (isdigit((unsigned char)c)) {
4508                                 /* take all digits */
4509                                 for (i = 0; t->input[t->offset + i] && isdigit((unsigned char)t->input[t->offset + i]);  i++);
4510 -                               
4511 +
4512                                 /* was there it least a digit ? */
4513 -                               if (i && t->input[t->offset + i]) {
4514 +                               if (i) {
4515                                         tid = TK_INTEGER;
4516 -                                       
4517 +
4518                                         buffer_copy_string_len(token, t->input + t->offset, i);
4519 -                                       
4520 +
4521                                         t->offset += i;
4522                                         t->line_pos += i;
4523 -                               } else {
4524 -                                       /* ERROR */
4525 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4526 -                                                       "source:", t->source,
4527 -                                                       "line:", t->line, "pos:", t->line_pos, 
4528 -                                                       "unexpected EOF");
4529 -                                       
4530 -                                       return -1;
4531                                 }
4532                         } else {
4533                                 /* the key might consist of [-.0-9a-z] */
4534 -                               for (i = 0; t->input[t->offset + i] && 
4535 -                                    (isalnum((unsigned char)t->input[t->offset + i]) || 
4536 +                               for (i = 0; t->input[t->offset + i] &&
4537 +                                    (isalnum((unsigned char)t->input[t->offset + i]) ||
4538                                       t->input[t->offset + i] == '.' ||
4539                                       t->input[t->offset + i] == '_' || /* for env.* */
4540                                       t->input[t->offset + i] == '-'
4541                                       ); i++);
4542 -                               
4543 +
4544                                 if (i && t->input[t->offset + i]) {
4545                                         buffer_copy_string_len(token, t->input + t->offset, i);
4546 -                                       
4547 -                                       if (strcmp(token->ptr, "include") == 0) {
4548 +
4549 +                                       if (buffer_is_equal_string(token, CONST_STR_LEN("include"))) {
4550                                                 tid = TK_INCLUDE;
4551 -                                       } else if (strcmp(token->ptr, "include_shell") == 0) {
4552 +                                       } else if (buffer_is_equal_string(token, CONST_STR_LEN("include_shell"))) {
4553                                                 tid = TK_INCLUDE_SHELL;
4554 -                                       } else if (strcmp(token->ptr, "global") == 0) {
4555 +                                       } else if (buffer_is_equal_string(token, CONST_STR_LEN("global"))) {
4556                                                 tid = TK_GLOBAL;
4557 -                                       } else if (strcmp(token->ptr, "else") == 0) {
4558 +                                       } else if (buffer_is_equal_string(token, CONST_STR_LEN("else"))) {
4559                                                 tid = TK_ELSE;
4560                                         } else {
4561                                                 tid = TK_LKEY;
4562                                         }
4563 -                                       
4564 +
4565                                         t->offset += i;
4566                                         t->line_pos += i;
4567                                 } else {
4568                                         /* ERROR */
4569 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4570 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4571                                                         "source:", t->source,
4572 -                                                       "line:", t->line, "pos:", t->line_pos, 
4573 +                                                       "line:", t->line, "pos:", t->line_pos,
4574                                                         "invalid character in variable name");
4575                                         return -1;
4576                                 }
4577 @@ -753,16 +752,16 @@
4578                         break;
4579                 }
4580         }
4581 -       
4582 +
4583         if (tid) {
4584                 *token_id = tid;
4585  #if 0
4586 -               log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd", 
4587 +               log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
4588                                 "source:", t->source,
4589                                 "line:", t->line, "pos:", t->line_pos,
4590                                 token, token->used - 1, tid);
4591  #endif
4592 -               
4593 +
4594                 return 1;
4595         } else if (t->offset < t->size) {
4596                 fprintf(stderr, "%s.%d: %d, %s\n",
4597 @@ -781,10 +780,11 @@
4598         pParser = configparserAlloc( malloc );
4599         lasttoken = buffer_init();
4600         token = buffer_init();
4601 +
4602         while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
4603                 buffer_copy_string_buffer(lasttoken, token);
4604                 configparser(pParser, token_id, token, context);
4605 -               
4606 +
4607                 token = buffer_init();
4608         }
4609         buffer_free(token);
4610 @@ -797,14 +797,14 @@
4611                 }
4612         }
4613         configparserFree(pParser, free);
4614 -       
4615 +
4616         if (ret == -1) {
4617 -               log_error_write(srv, __FILE__, __LINE__, "sb", 
4618 +               log_error_write(srv, __FILE__, __LINE__, "sb",
4619                                 "configfile parser failed:", lasttoken);
4620         } else if (context->ok == 0) {
4621 -               log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb", 
4622 +               log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
4623                                 "source:", t->source,
4624 -                               "line:", t->line, "pos:", t->line_pos, 
4625 +                               "line:", t->line, "pos:", t->line_pos,
4626                                 "parser failed somehow near here:", lasttoken);
4627                 ret = -1;
4628         }
4629 @@ -821,7 +821,7 @@
4630         t->offset = 0;
4631         t->line = 1;
4632         t->line_pos = 1;
4633 -       
4634 +
4635         t->in_key = 1;
4636         t->in_brace = 0;
4637         t->in_cond = 0;
4638 @@ -844,7 +844,7 @@
4639         }
4640  
4641         if (0 != stream_open(&s, filename)) {
4642 -               log_error_write(srv, __FILE__, __LINE__, "sbss", 
4643 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
4644                                 "opening configfile ", filename, "failed:", strerror(errno));
4645                 ret = -1;
4646         } else {
4647 @@ -866,7 +866,7 @@
4648         char oldpwd[PATH_MAX];
4649  
4650         if (NULL == getcwd(oldpwd, sizeof(oldpwd))) {
4651 -               log_error_write(srv, __FILE__, __LINE__, "s", 
4652 +               log_error_write(srv, __FILE__, __LINE__, "s",
4653                                 "cannot get cwd", strerror(errno));
4654                 return -1;
4655         }
4656 @@ -879,7 +879,7 @@
4657         }
4658  
4659         if (0 != proc_open_buffer(&proc, cmd, NULL, out, NULL)) {
4660 -               log_error_write(srv, __FILE__, __LINE__, "sbss", 
4661 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
4662                                 "opening", source, "failed:", strerror(errno));
4663                 ret = -1;
4664         } else {
4665 @@ -896,13 +896,12 @@
4666  static void context_init(server *srv, config_t *context) {
4667         context->srv = srv;
4668         context->ok = 1;
4669 -       context->configs_stack = array_init();
4670 -       context->configs_stack->is_weakref = 1;
4671 +       context->configs_stack = buffer_ptr_init(NULL);
4672         context->basedir = buffer_init();
4673  }
4674  
4675  static void context_free(config_t *context) {
4676 -       array_free(context->configs_stack);
4677 +       buffer_ptr_free(context->configs_stack);
4678         buffer_free(context->basedir);
4679  }
4680  
4681 @@ -918,18 +917,15 @@
4682         context_init(srv, &context);
4683         context.all_configs = srv->config_context;
4684  
4685 -       pos = strrchr(fn,
4686 -#ifdef __WIN32
4687 -                       '\\'
4688 -#else
4689 -                       '/'
4690 -#endif
4691 -                       );
4692 +    /* use the current dir as basedir for all other includes
4693 +    */
4694 +       pos = strrchr(fn, DIR_SEPERATOR);
4695 +
4696         if (pos) {
4697                 buffer_copy_string_len(context.basedir, fn, pos - fn + 1);
4698                 fn = pos + 1;
4699         }
4700 -       
4701 +
4702         dc = data_config_init();
4703         buffer_copy_string(dc->key, "global");
4704  
4705 @@ -944,7 +940,7 @@
4706         dpid->value = getpid();
4707         buffer_copy_string(dpid->key, "var.PID");
4708         array_insert_unique(srv->config, (data_unset *)dpid);
4709 -       
4710 +
4711         dcwd = data_string_init();
4712         buffer_prepare_copy(dcwd->value, 1024);
4713         if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) {
4714 @@ -968,7 +964,7 @@
4715         } else {
4716                 return -1;
4717         }
4718 -       
4719 +
4720         if (NULL != (modules = (data_array *)array_get_element(srv->config, "server.modules"))) {
4721                 data_string *ds;
4722                 data_array *prepends;
4723 @@ -1026,22 +1022,23 @@
4724                 buffer_copy_string(modules->key, "server.modules");
4725                 array_insert_unique(srv->config, (data_unset *)modules);
4726         }
4727 -       
4728 +
4729  
4730         if (0 != config_insert(srv)) {
4731                 return -1;
4732         }
4733 -       
4734 +
4735         return 0;
4736  }
4737  
4738 +
4739  int config_set_defaults(server *srv) {
4740         size_t i;
4741         specific_config *s = srv->config_storage[0];
4742         struct stat st1, st2;
4743 -       
4744 -       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] = 
4745 -       { 
4746 +
4747 +       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
4748 +       {
4749                 /* - poll is most reliable
4750                  * - select works everywhere
4751                  * - linux-* are experimental
4752 @@ -1067,20 +1064,21 @@
4753  #endif
4754                 { FDEVENT_HANDLER_UNSET,          NULL }
4755         };
4756 -       
4757  
4758 -       if (buffer_is_empty(s->document_root)) {  
4759 -               log_error_write(srv, __FILE__, __LINE__, "s",  
4760 -                               "a default document-root has to be set");  
4761 -               
4762 -               return -1;  
4763 -       }  
4764 -       
4765 +
4766 +       if (buffer_is_empty(s->document_root)) {
4767 +               log_error_write(srv, __FILE__, __LINE__, "s",
4768 +                               "a default document-root has to be set");
4769 +
4770 +               return -1;
4771 +       }
4772 +
4773         if (buffer_is_empty(srv->srvconf.changeroot)) {
4774 -               if (-1 == stat(s->document_root->ptr, &st1)) {  
4775 -                       log_error_write(srv, __FILE__, __LINE__, "sb",  
4776 +        pathname_unix2local(s->document_root);
4777 +               if (-1 == stat(s->document_root->ptr, &st1)) {
4778 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
4779                                         "base-docroot doesn't exist:",
4780 -                                       s->document_root);  
4781 +                                       s->document_root, strerror(errno));
4782                         return -1;
4783                 }
4784  
4785 @@ -1088,18 +1086,18 @@
4786                 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.changeroot);
4787                 buffer_append_string_buffer(srv->tmp_buf, s->document_root);
4788  
4789 -               if (-1 == stat(srv->tmp_buf->ptr, &st1)) {  
4790 -                       log_error_write(srv, __FILE__, __LINE__, "sb",  
4791 +               if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
4792 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
4793                                         "base-docroot doesn't exist:",
4794 -                                       srv->tmp_buf);  
4795 +                                       srv->tmp_buf);
4796                         return -1;
4797                 }
4798 -               
4799 +
4800         }
4801 -       
4802 -       buffer_copy_string_buffer(srv->tmp_buf, s->document_root);  
4803  
4804 -       buffer_to_lower(srv->tmp_buf);  
4805 +       buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4806 +
4807 +       buffer_to_lower(srv->tmp_buf);
4808  
4809         if (0 == stat(srv->tmp_buf->ptr, &st1)) {
4810                 int is_lower = 0;
4811 @@ -1107,68 +1105,68 @@
4812                 is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);
4813  
4814                 /* lower-case existed, check upper-case */
4815 -               buffer_copy_string_buffer(srv->tmp_buf, s->document_root);  
4816 +               buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4817  
4818 -               buffer_to_upper(srv->tmp_buf);  
4819 +               buffer_to_upper(srv->tmp_buf);
4820  
4821                 /* we have to handle the special case that upper and lower-casing results in the same filename
4822                  * as in server.document-root = "/" or "/12345/" */
4823  
4824                 if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
4825 -                       /* lower-casing and upper-casing didn't result in  
4826 -                        * an other filename, no need to stat(), 
4827 +                       /* lower-casing and upper-casing didn't result in
4828 +                        * an other filename, no need to stat(),
4829                          * just assume it is case-sensitive. */
4830  
4831                         s->force_lowercase_filenames = 0;
4832 -               } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {  
4833 +               } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
4834 +
4835 +                       /* upper case exists too, doesn't the FS handle this ? */
4836 +
4837 +                       /* upper and lower have the same inode -> case-insensitve FS */
4838 +
4839 +                       if (st1.st_ino == st2.st_ino) {
4840 +                               /* upper and lower have the same inode -> case-insensitve FS */
4841 +
4842 +                               s->force_lowercase_filenames = 1;
4843 +                       }
4844 +               }
4845 +       }
4846  
4847 -                       /* upper case exists too, doesn't the FS handle this ? */  
4848 -                       
4849 -                       /* upper and lower have the same inode -> case-insensitve FS */  
4850 -                       
4851 -                       if (st1.st_ino == st2.st_ino) {  
4852 -                               /* upper and lower have the same inode -> case-insensitve FS */  
4853 -                               
4854 -                               s->force_lowercase_filenames = 1;  
4855 -                       }  
4856 -               }  
4857 -       }  
4858 -       
4859         if (srv->srvconf.port == 0) {
4860                 srv->srvconf.port = s->is_ssl ? 443 : 80;
4861         }
4862 -       
4863 +
4864         if (srv->srvconf.event_handler->used == 0) {
4865                 /* choose a good default
4866 -                * 
4867 -                * the event_handler list is sorted by 'goodness' 
4868 +                *
4869 +                * the event_handler list is sorted by 'goodness'
4870                  * taking the first available should be the best solution
4871                  */
4872                 srv->event_handler = event_handlers[0].et;
4873 -               
4874 +
4875                 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
4876 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
4877 +                       log_error_write(srv, __FILE__, __LINE__, "s",
4878                                         "sorry, there is no event handler for this system");
4879 -                       
4880 +
4881                         return -1;
4882                 }
4883         } else {
4884                 /*
4885                  * User override
4886                  */
4887 -               
4888 +
4889                 for (i = 0; event_handlers[i].name; i++) {
4890                         if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) {
4891                                 srv->event_handler = event_handlers[i].et;
4892                                 break;
4893                         }
4894                 }
4895 -               
4896 +
4897                 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
4898 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
4899 -                                       "the selected event-handler in unknown or not supported:", 
4900 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
4901 +                                       "the selected event-handler in unknown or not supported:",
4902                                         srv->srvconf.event_handler );
4903 -                       
4904 +
4905                         return -1;
4906                 }
4907         }
4908 @@ -1176,19 +1174,19 @@
4909         if (s->is_ssl) {
4910                 if (buffer_is_empty(s->ssl_pemfile)) {
4911                         /* PEM file is require */
4912 -                       
4913 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
4914 +
4915 +                       log_error_write(srv, __FILE__, __LINE__, "s",
4916                                         "ssl.pemfile has to be set");
4917                         return -1;
4918                 }
4919 -               
4920 +
4921  #ifndef USE_OPENSSL
4922 -               log_error_write(srv, __FILE__, __LINE__, "s", 
4923 +               log_error_write(srv, __FILE__, __LINE__, "s",
4924                                 "ssl support is missing, recompile with --with-openssl");
4925 -               
4926 +
4927                 return -1;
4928  #endif
4929         }
4930 -       
4931 +
4932         return 0;
4933  }
4934 --- ../lighttpd-1.4.11/src/configfile.h 2005-08-23 17:36:12.000000000 +0300
4935 +++ lighttpd-1.4.12/src/configfile.h    2006-07-16 00:26:03.000000000 +0300
4936 @@ -9,7 +9,7 @@
4937         server *srv;
4938         int     ok;
4939         array  *all_configs;
4940 -       array  *configs_stack; /* to parse nested block */
4941 +       buffer_ptr  *configs_stack; /* to parse nested block */
4942         data_config *current; /* current started with { */
4943         buffer *basedir;
4944  } config_t;
4945 --- ../lighttpd-1.4.11/src/configparser.c       2006-02-01 19:51:15.000000000 +0200
4946 +++ lighttpd-1.4.12/src/configparser.c  2006-07-17 22:02:23.000000000 +0300
4947 @@ -24,52 +24,34 @@
4948      dc->parent = ctx->current;
4949      array_insert_unique(dc->parent->childs, (data_unset *)dc);
4950    }
4951 -  array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
4952 +  buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
4953    ctx->current = dc;
4954  }
4955  
4956  static data_config *configparser_pop(config_t *ctx) {
4957    data_config *old = ctx->current;
4958 -  ctx->current = (data_config *) array_pop(ctx->configs_stack);
4959 +  ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
4960    return old;
4961  }
4962  
4963  /* return a copied variable */
4964  static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
4965 -  if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
4966 -    char *env;
4967 -
4968 -    if (NULL != (env = getenv(key->ptr + 4))) {
4969 -      data_string *ds;
4970 -      ds = data_string_init();
4971 -      buffer_append_string(ds->value, env);
4972 -      return (data_unset *)ds;
4973 -    }
4974 -
4975 -    fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
4976 -    ctx->ok = 0;
4977 -
4978 -    return NULL;
4979 -  } else {
4980 -    data_unset *du;
4981 -    data_config *dc;
4982 +  data_unset *du;
4983 +  data_config *dc;
4984  
4985  #if 0
4986 -    fprintf(stderr, "get var %s\n", key->ptr);
4987 +  fprintf(stderr, "get var %s\n", key->ptr);
4988  #endif
4989 -    for (dc = ctx->current; dc; dc = dc->parent) {
4990 +  for (dc = ctx->current; dc; dc = dc->parent) {
4991  #if 0
4992 -      fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
4993 -      array_print(dc->value, 0);
4994 +    fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
4995 +    array_print(dc->value, 0);
4996  #endif
4997 -      if (NULL != (du = array_get_element(dc->value, key->ptr))) {
4998 -        return du->copy(du);
4999 -      }
5000 +    if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5001 +      return du->copy(du);
5002      }
5003 -    fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
5004 -    ctx->ok = 0;
5005 -    return NULL;
5006    }
5007 +  return NULL;
5008  }
5009  
5010  /* op1 is to be eat/return by this function, op1->key is not cared
5011 @@ -124,14 +106,14 @@
5012  }
5013  
5014  
5015 -#line 128 "configparser.c"
5016 +#line 110 "configparser.c"
5017  /* Next is all token values, in a form suitable for use by makeheaders.
5018  ** This section will be null unless lemon is run with the -m switch.
5019  */
5020 -/* 
5021 +/*
5022  ** These constants (all generated automatically by the parser generator)
5023  ** specify the various kinds of tokens (terminals) that the parser
5024 -** understands. 
5025 +** understands.
5026  **
5027  ** Each symbol here is a terminal symbol in the grammar.
5028  */
5029 @@ -148,7 +130,7 @@
5030  **                       and nonterminals.  "int" is used otherwise.
5031  **    YYNOCODE           is a number of type YYCODETYPE which corresponds
5032  **                       to no legal terminal or nonterminal number.  This
5033 -**                       number is used to fill in empty slots of the hash 
5034 +**                       number is used to fill in empty slots of the hash
5035  **                       table.
5036  **    YYFALLBACK         If defined, this indicates that one or more tokens
5037  **                       have fall-back values which should be used if the
5038 @@ -157,7 +139,7 @@
5039  **                       and nonterminal numbers.  "unsigned char" is
5040  **                       used if there are fewer than 250 rules and
5041  **                       states combined.  "int" is used otherwise.
5042 -**    configparserTOKENTYPE     is the data type used for minor tokens given 
5043 +**    configparserTOKENTYPE     is the data type used for minor tokens given
5044  **                       directly to the parser from the tokenizer.
5045  **    YYMINORTYPE        is the data type used for all minor tokens.
5046  **                       This is typically a union of many types, one of
5047 @@ -192,8 +174,8 @@
5048  #define configparserARG_PDECL ,config_t *ctx
5049  #define configparserARG_FETCH config_t *ctx = yypParser->ctx
5050  #define configparserARG_STORE yypParser->ctx = ctx
5051 -#define YYNSTATE 62
5052 -#define YYNRULE 39
5053 +#define YYNSTATE 63
5054 +#define YYNRULE 40
5055  #define YYERRORSYMBOL 26
5056  #define YYERRSYMDT yy95
5057  #define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
5058 @@ -203,7 +185,7 @@
5059  /* Next are that tables used to determine what action to take based on the
5060  ** current state and lookahead token.  These tables are used to implement
5061  ** functions that take a state number and lookahead value and return an
5062 -** action integer.  
5063 +** action integer.
5064  **
5065  ** Suppose the action integer is N.  Then the action is determined as
5066  ** follows
5067 @@ -228,7 +210,7 @@
5068  ** If the index value yy_shift_ofst[S]+X is out of range or if the value
5069  ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
5070  ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
5071 -** and that yy_default[S] should be used instead.  
5072 +** and that yy_default[S] should be used instead.
5073  **
5074  ** The formula above is for computing the action when the lookahead is
5075  ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
5076 @@ -248,67 +230,69 @@
5077  **  yy_default[]       Default action for each state.
5078  */
5079  static YYACTIONTYPE yy_action[] = {
5080 - /*     0 */     2,    3,    4,    5,   13,   14,   62,   15,    7,   44,
5081 - /*    10 */    20,   86,   16,   45,   28,   48,   40,   10,   39,   25,
5082 - /*    20 */    22,   49,   45,    8,   15,  102,    1,   20,   28,   18,
5083 - /*    30 */    57,   59,   19,   25,   22,   39,   19,   61,   98,   45,
5084 - /*    40 */    20,    6,   23,   24,   26,   28,   35,   57,   59,   12,
5085 - /*    50 */    25,   22,   28,   27,   36,   87,   29,   25,   22,   33,
5086 - /*    60 */    15,   30,   31,   20,   28,   38,    9,   17,   37,   25,
5087 - /*    70 */    22,   39,   42,   43,   10,   45,   11,   53,   54,   55,
5088 - /*    80 */    56,   28,   52,   57,   59,   34,   25,   22,   28,   27,
5089 - /*    90 */    32,   88,   41,   25,   22,   33,   28,   48,   46,   28,
5090 - /*   100 */    48,   25,   22,   58,   25,   22,   60,   21,   19,   47,
5091 - /*   110 */    51,   50,   25,   22,   88,   88,   93,
5092 + /*     0 */     2,    3,    4,    5,   13,   14,   63,   15,    7,   45,
5093 + /*    10 */    20,   88,   16,   46,   28,   49,   41,   10,   40,   25,
5094 + /*    20 */    22,   50,   46,    8,   15,  104,    1,   20,   28,   18,
5095 + /*    30 */    58,   60,    6,   25,   22,   40,   47,   62,   11,   46,
5096 + /*    40 */    20,    9,   23,   24,   26,   29,   89,   58,   60,   10,
5097 + /*    50 */    17,   38,   28,   27,   37,   19,   30,   25,   22,   34,
5098 + /*    60 */    15,  100,   20,   20,   23,   24,   26,   12,   19,   31,
5099 + /*    70 */    32,   40,   19,   44,   43,   46,   95,   35,   90,   89,
5100 + /*    80 */    28,   49,   42,   58,   60,   25,   22,   59,   28,   27,
5101 + /*    90 */    33,   48,   52,   25,   22,   34,   28,   49,   51,   28,
5102 + /*   100 */    36,   25,   22,   61,   25,   22,   89,   28,   39,   89,
5103 + /*   110 */    89,   89,   25,   22,   54,   55,   56,   57,   89,   28,
5104 + /*   120 */    53,   21,   89,   89,   25,   22,   25,   22,
5105  };
5106  static YYCODETYPE yy_lookahead[] = {
5107   /*     0 */    29,   30,   31,   32,   33,   34,    0,    1,   44,   38,
5108   /*    10 */     4,   15,   41,   16,   35,   36,   45,   46,   12,   40,
5109   /*    20 */    41,   42,   16,   15,    1,   27,   28,    4,   35,   36,
5110 - /*    30 */    24,   25,    5,   40,   41,   12,    5,   14,   11,   16,
5111 - /*    40 */     4,    1,    6,    7,    8,   35,   36,   24,   25,   28,
5112 - /*    50 */    40,   41,   35,   36,   37,   15,   39,   40,   41,   42,
5113 - /*    60 */     1,    9,   10,    4,   35,   36,   38,    2,    3,   40,
5114 - /*    70 */    41,   12,   28,   14,   46,   16,   13,   20,   21,   22,
5115 - /*    80 */    23,   35,   36,   24,   25,   11,   40,   41,   35,   36,
5116 - /*    90 */    37,   13,   13,   40,   41,   42,   35,   36,   17,   35,
5117 - /*   100 */    36,   40,   41,   42,   40,   41,   42,   35,    5,   18,
5118 - /*   110 */    43,   19,   40,   41,   47,   47,   13,
5119 + /*    30 */    24,   25,    1,   40,   41,   12,   17,   14,   13,   16,
5120 + /*    40 */     4,   38,    6,    7,    8,    9,   15,   24,   25,   46,
5121 + /*    50 */     2,    3,   35,   36,   37,    5,   39,   40,   41,   42,
5122 + /*    60 */     1,   11,    4,    4,    6,    7,    8,   28,    5,    9,
5123 + /*    70 */    10,   12,    5,   14,   28,   16,   13,   11,   13,   47,
5124 + /*    80 */    35,   36,   13,   24,   25,   40,   41,   42,   35,   36,
5125 + /*    90 */    37,   18,   43,   40,   41,   42,   35,   36,   19,   35,
5126 + /*   100 */    36,   40,   41,   42,   40,   41,   47,   35,   36,   47,
5127 + /*   110 */    47,   47,   40,   41,   20,   21,   22,   23,   47,   35,
5128 + /*   120 */    36,   35,   47,   47,   40,   41,   40,   41,
5129  };
5130  #define YY_SHIFT_USE_DFLT (-5)
5131  static signed char yy_shift_ofst[] = {
5132 - /*     0 */    -5,    6,   -5,   -5,   -5,   40,   -4,    8,   -3,   -5,
5133 - /*    10 */    63,   -5,   23,   -5,   -5,   -5,   65,   36,   31,   36,
5134 - /*    20 */    -5,   -5,   -5,   -5,   -5,   -5,   36,   27,   -5,   52,
5135 - /*    30 */    -5,   36,   -5,   74,   36,   31,   -5,   36,   31,   78,
5136 - /*    40 */    79,   -5,   59,   -5,   -5,   81,   91,   36,   31,   92,
5137 - /*    50 */    57,   36,  103,   -5,   -5,   -5,   -5,   36,   -5,   36,
5138 - /*    60 */    -5,   -5,
5139 + /*     0 */    -5,    6,   -5,   -5,   -5,   31,   -4,    8,   -3,   -5,
5140 + /*    10 */    25,   -5,   23,   -5,   -5,   -5,   48,   58,   67,   58,
5141 + /*    20 */    -5,   -5,   -5,   -5,   -5,   -5,   36,   50,   -5,   -5,
5142 + /*    30 */    60,   -5,   58,   -5,   66,   58,   67,   -5,   58,   67,
5143 + /*    40 */    65,   69,   -5,   59,   -5,   -5,   19,   73,   58,   67,
5144 + /*    50 */    79,   94,   58,   63,   -5,   -5,   -5,   -5,   58,   -5,
5145 + /*    60 */    58,   -5,   -5,
5146  };
5147  #define YY_REDUCE_USE_DFLT (-37)
5148  static signed char yy_reduce_ofst[] = {
5149 - /*     0 */    -2,  -29,  -37,  -37,  -37,  -36,  -37,  -37,   28,  -37,
5150 - /*    10 */   -37,   21,  -29,  -37,  -37,  -37,  -37,   -7,  -37,   72,
5151 + /*     0 */    -2,  -29,  -37,  -37,  -37,  -36,  -37,  -37,    3,  -37,
5152 + /*    10 */   -37,   39,  -29,  -37,  -37,  -37,  -37,   -7,  -37,   86,
5153   /*    20 */   -37,  -37,  -37,  -37,  -37,  -37,   17,  -37,  -37,  -37,
5154 - /*    30 */   -37,   53,  -37,  -37,   10,  -37,  -37,   29,  -37,  -37,
5155 - /*    40 */   -37,   44,  -29,  -37,  -37,  -37,  -37,  -21,  -37,  -37,
5156 - /*    50 */    67,   46,  -37,  -37,  -37,  -37,  -37,   61,  -37,   64,
5157 - /*    60 */   -37,  -37,
5158 + /*    30 */   -37,  -37,   53,  -37,  -37,   64,  -37,  -37,   72,  -37,
5159 + /*    40 */   -37,  -37,   46,  -29,  -37,  -37,  -37,  -37,  -21,  -37,
5160 + /*    50 */   -37,   49,   84,  -37,  -37,  -37,  -37,  -37,   45,  -37,
5161 + /*    60 */    61,  -37,  -37,
5162  };
5163  static YYACTIONTYPE yy_default[] = {
5164 - /*     0 */    64,  101,   63,   65,   66,  101,   67,  101,  101,   90,
5165 - /*    10 */   101,   64,  101,   68,   69,   70,  101,  101,   71,  101,
5166 - /*    20 */    73,   74,   76,   77,   78,   79,  101,   84,   75,  101,
5167 - /*    30 */    80,   82,   81,  101,  101,   85,   83,  101,   72,  101,
5168 - /*    40 */   101,   64,  101,   89,   91,  101,  101,  101,   98,  101,
5169 - /*    50 */   101,  101,  101,   94,   95,   96,   97,  101,   99,  101,
5170 - /*    60 */   100,   92,
5171 + /*     0 */    65,  103,   64,   66,   67,  103,   68,  103,  103,   92,
5172 + /*    10 */   103,   65,  103,   69,   70,   71,  103,  103,   72,  103,
5173 + /*    20 */    74,   75,   77,   78,   79,   80,  103,   86,   76,   81,
5174 + /*    30 */   103,   82,   84,   83,  103,  103,   87,   85,  103,   73,
5175 + /*    40 */   103,  103,   65,  103,   91,   93,  103,  103,  103,  100,
5176 + /*    50 */   103,  103,  103,  103,   96,   97,   98,   99,  103,  101,
5177 + /*    60 */   103,  102,   94,
5178  };
5179  #define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
5180  
5181  /* The next table maps tokens into fallback tokens.  If a construct
5182  ** like the following:
5183 -** 
5184 +**
5185  **      %fallback ID X Y Z.
5186  **
5187  ** appears in the grammer, then ID becomes a fallback token for X, Y,
5188 @@ -359,10 +343,10 @@
5189  #endif /* NDEBUG */
5190  
5191  #ifndef NDEBUG
5192 -/* 
5193 +/*
5194  ** Turn parser tracing on by giving a stream to which to write the trace
5195  ** and a prompt to preface each trace message.  Tracing is turned off
5196 -** by making either argument NULL 
5197 +** by making either argument NULL
5198  **
5199  ** Inputs:
5200  ** <ul>
5201 @@ -387,7 +371,7 @@
5202  #ifndef NDEBUG
5203  /* For tracing shifts, the names of all terminals and nonterminals
5204  ** are required.  The following table supplies these names */
5205 -static const char *yyTokenName[] = { 
5206 +static const char *yyTokenName[] = {
5207    "$",             "EOL",           "ASSIGN",        "APPEND",      
5208    "LKEY",          "PLUS",          "STRING",        "INTEGER",     
5209    "LPARAN",        "RPARAN",        "COMMA",         "ARRAY_ASSIGN",
5210 @@ -425,27 +409,28 @@
5211   /*  15 */ "value ::= STRING",
5212   /*  16 */ "value ::= INTEGER",
5213   /*  17 */ "value ::= array",
5214 - /*  18 */ "array ::= LPARAN aelements RPARAN",
5215 - /*  19 */ "aelements ::= aelements COMMA aelement",
5216 - /*  20 */ "aelements ::= aelements COMMA",
5217 - /*  21 */ "aelements ::= aelement",
5218 - /*  22 */ "aelement ::= expression",
5219 - /*  23 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5220 - /*  24 */ "eols ::= EOL",
5221 - /*  25 */ "eols ::=",
5222 - /*  26 */ "globalstart ::= GLOBAL",
5223 - /*  27 */ "global ::= globalstart LCURLY metalines RCURLY",
5224 - /*  28 */ "condlines ::= condlines eols ELSE condline",
5225 - /*  29 */ "condlines ::= condline",
5226 - /*  30 */ "condline ::= context LCURLY metalines RCURLY",
5227 - /*  31 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5228 - /*  32 */ "cond ::= EQ",
5229 - /*  33 */ "cond ::= MATCH",
5230 - /*  34 */ "cond ::= NE",
5231 - /*  35 */ "cond ::= NOMATCH",
5232 - /*  36 */ "stringop ::= expression",
5233 - /*  37 */ "include ::= INCLUDE stringop",
5234 - /*  38 */ "include_shell ::= INCLUDE_SHELL stringop",
5235 + /*  18 */ "array ::= LPARAN RPARAN",
5236 + /*  19 */ "array ::= LPARAN aelements RPARAN",
5237 + /*  20 */ "aelements ::= aelements COMMA aelement",
5238 + /*  21 */ "aelements ::= aelements COMMA",
5239 + /*  22 */ "aelements ::= aelement",
5240 + /*  23 */ "aelement ::= expression",
5241 + /*  24 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5242 + /*  25 */ "eols ::= EOL",
5243 + /*  26 */ "eols ::=",
5244 + /*  27 */ "globalstart ::= GLOBAL",
5245 + /*  28 */ "global ::= globalstart LCURLY metalines RCURLY",
5246 + /*  29 */ "condlines ::= condlines eols ELSE condline",
5247 + /*  30 */ "condlines ::= condline",
5248 + /*  31 */ "condline ::= context LCURLY metalines RCURLY",
5249 + /*  32 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5250 + /*  33 */ "cond ::= EQ",
5251 + /*  34 */ "cond ::= MATCH",
5252 + /*  35 */ "cond ::= NE",
5253 + /*  36 */ "cond ::= NOMATCH",
5254 + /*  37 */ "stringop ::= expression",
5255 + /*  38 */ "include ::= INCLUDE stringop",
5256 + /*  39 */ "include_shell ::= INCLUDE_SHELL stringop",
5257  };
5258  #endif /* NDEBUG */
5259  
5260 @@ -465,7 +450,7 @@
5261  #endif
5262  }
5263  
5264 -/* 
5265 +/*
5266  ** This function allocates a new parser.
5267  ** The only argument is a pointer to a function which works like
5268  ** malloc.
5269 @@ -496,7 +481,7 @@
5270      /* Here is inserted the actions which take place when a
5271      ** terminal or non-terminal is destroyed.  This can happen
5272      ** when the symbol is popped from the stack during a
5273 -    ** reduce or during error processing or when a parser is 
5274 +    ** reduce or during error processing or when a parser is
5275      ** being destroyed before it is finished parsing.
5276      **
5277      ** Note: during a reduce, the only symbols destroyed are those
5278 @@ -528,44 +513,44 @@
5279      case 23:
5280      case 24:
5281      case 25:
5282 -#line 160 "./configparser.y"
5283 +#line 143 "./configparser.y"
5284  { buffer_free((yypminor->yy0)); }
5285 -#line 533 "configparser.c"
5286 +#line 518 "configparser.c"
5287        break;
5288      case 35:
5289 -#line 151 "./configparser.y"
5290 +#line 134 "./configparser.y"
5291  { (yypminor->yy41)->free((yypminor->yy41)); }
5292 -#line 538 "configparser.c"
5293 +#line 523 "configparser.c"
5294        break;
5295      case 36:
5296 -#line 152 "./configparser.y"
5297 +#line 135 "./configparser.y"
5298  { (yypminor->yy41)->free((yypminor->yy41)); }
5299 -#line 543 "configparser.c"
5300 +#line 528 "configparser.c"
5301        break;
5302      case 37:
5303 -#line 153 "./configparser.y"
5304 +#line 136 "./configparser.y"
5305  { (yypminor->yy41)->free((yypminor->yy41)); }
5306 -#line 548 "configparser.c"
5307 +#line 533 "configparser.c"
5308        break;
5309      case 39:
5310 -#line 154 "./configparser.y"
5311 +#line 137 "./configparser.y"
5312  { array_free((yypminor->yy40)); }
5313 -#line 553 "configparser.c"
5314 +#line 538 "configparser.c"
5315        break;
5316      case 40:
5317 -#line 155 "./configparser.y"
5318 +#line 138 "./configparser.y"
5319  { array_free((yypminor->yy40)); }
5320 -#line 558 "configparser.c"
5321 +#line 543 "configparser.c"
5322        break;
5323      case 41:
5324 -#line 156 "./configparser.y"
5325 +#line 139 "./configparser.y"
5326  { buffer_free((yypminor->yy43)); }
5327 -#line 563 "configparser.c"
5328 +#line 548 "configparser.c"
5329        break;
5330      case 42:
5331 -#line 157 "./configparser.y"
5332 +#line 140 "./configparser.y"
5333  { buffer_free((yypminor->yy43)); }
5334 -#line 568 "configparser.c"
5335 +#line 553 "configparser.c"
5336        break;
5337      default:  break;   /* If no destructor action specified: do nothing */
5338    }
5339 @@ -597,7 +582,7 @@
5340    return yymajor;
5341  }
5342  
5343 -/* 
5344 +/*
5345  ** Deallocate and destroy a parser.  Destructors are all called for
5346  ** all stack elements before shutting the parser down.
5347  **
5348 @@ -633,7 +618,7 @@
5349  ){
5350    int i;
5351    int stateno = pParser->yystack[pParser->yyidx].stateno;
5352
5353 +
5354    /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
5355    i = yy_shift_ofst[stateno];
5356    if( i==YY_SHIFT_USE_DFLT ){
5357 @@ -677,7 +662,7 @@
5358  ){
5359    int i;
5360    int stateno = pParser->yystack[pParser->yyidx].stateno;
5361
5362 +
5363    i = yy_reduce_ofst[stateno];
5364    if( i==YY_REDUCE_USE_DFLT ){
5365      return yy_default[stateno];
5366 @@ -759,6 +744,7 @@
5367    { 35, 1 },
5368    { 35, 1 },
5369    { 35, 1 },
5370 +  { 40, 2 },
5371    { 40, 3 },
5372    { 39, 3 },
5373    { 39, 2 },
5374 @@ -800,7 +786,7 @@
5375    configparserARG_FETCH;
5376    yymsp = &yypParser->yystack[yypParser->yyidx];
5377  #ifndef NDEBUG
5378 -  if( yyTraceFILE && yyruleno>=0 
5379 +  if( yyTraceFILE && yyruleno>=0
5380          && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
5381      fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
5382        yyRuleName[yyruleno]);
5383 @@ -832,9 +818,9 @@
5384          /* No destructor defined for global */
5385          break;
5386        case 5:
5387 -#line 134 "./configparser.y"
5388 +#line 116 "./configparser.y"
5389  { yymsp[-1].minor.yy78 = NULL; }
5390 -#line 837 "configparser.c"
5391 +#line 823 "configparser.c"
5392    yy_destructor(1,&yymsp[0].minor);
5393          break;
5394        case 6:
5395 @@ -847,10 +833,15 @@
5396    yy_destructor(1,&yymsp[0].minor);
5397          break;
5398        case 9:
5399 -#line 162 "./configparser.y"
5400 +#line 145 "./configparser.y"
5401  {
5402    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5403 -  if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5404 +  if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5405 +    fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
5406 +        ctx->current->context_ndx,
5407 +        ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5408 +    ctx->ok = 0;
5409 +  } else if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5410      array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5411      yymsp[0].minor.yy41 = NULL;
5412    } else {
5413 @@ -864,16 +855,21 @@
5414    buffer_free(yymsp[-2].minor.yy43);
5415    yymsp[-2].minor.yy43 = NULL;
5416  }
5417 -#line 867 "configparser.c"
5418 +#line 858 "configparser.c"
5419    yy_destructor(2,&yymsp[-1].minor);
5420          break;
5421        case 10:
5422 -#line 179 "./configparser.y"
5423 +#line 167 "./configparser.y"
5424  {
5425    array *vars = ctx->current->value;
5426    data_unset *du;
5427  
5428 -  if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5429 +  if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5430 +    fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
5431 +        ctx->current->context_ndx,
5432 +        ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5433 +    ctx->ok = 0;
5434 +  } else if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5435      /* exists in current block */
5436      du = configparser_merge_data(du, yymsp[0].minor.yy41);
5437      if (NULL == du) {
5438 @@ -883,6 +879,7 @@
5439        buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5440        array_replace(vars, du);
5441      }
5442 +    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5443    } else if (NULL != (du = configparser_get_variable(ctx, yymsp[-2].minor.yy43))) {
5444      du = configparser_merge_data(du, yymsp[0].minor.yy41);
5445      if (NULL == du) {
5446 @@ -892,22 +889,20 @@
5447        buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5448        array_insert_unique(ctx->current->value, du);
5449      }
5450 +    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5451    } else {
5452 -    fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n", 
5453 -            ctx->current->context_ndx,
5454 -            ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5455 -    ctx->ok = 0;
5456 +    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5457 +    array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5458    }
5459    buffer_free(yymsp[-2].minor.yy43);
5460    yymsp[-2].minor.yy43 = NULL;
5461 -  yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5462    yymsp[0].minor.yy41 = NULL;
5463  }
5464 -#line 906 "configparser.c"
5465 +#line 901 "configparser.c"
5466    yy_destructor(3,&yymsp[-1].minor);
5467          break;
5468        case 11:
5469 -#line 214 "./configparser.y"
5470 +#line 206 "./configparser.y"
5471  {
5472    if (strchr(yymsp[0].minor.yy0->ptr, '.') == NULL) {
5473      yygotominor.yy43 = buffer_init_string("var.");
5474 @@ -919,10 +914,10 @@
5475      yymsp[0].minor.yy0 = NULL;
5476    }
5477  }
5478 -#line 922 "configparser.c"
5479 +#line 917 "configparser.c"
5480          break;
5481        case 12:
5482 -#line 226 "./configparser.y"
5483 +#line 218 "./configparser.y"
5484  {
5485    yygotominor.yy41 = configparser_merge_data(yymsp[-2].minor.yy41, yymsp[0].minor.yy41);
5486    if (NULL == yygotominor.yy41) {
5487 @@ -932,21 +927,38 @@
5488    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5489    yymsp[0].minor.yy41 = NULL;
5490  }
5491 -#line 935 "configparser.c"
5492 +#line 930 "configparser.c"
5493    yy_destructor(5,&yymsp[-1].minor);
5494          break;
5495        case 13:
5496 -#line 236 "./configparser.y"
5497 +#line 228 "./configparser.y"
5498  {
5499    yygotominor.yy41 = yymsp[0].minor.yy41;
5500    yymsp[0].minor.yy41 = NULL;
5501  }
5502 -#line 944 "configparser.c"
5503 +#line 939 "configparser.c"
5504          break;
5505        case 14:
5506 -#line 241 "./configparser.y"
5507 +#line 233 "./configparser.y"
5508  {
5509 -  yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43);
5510 +  if (strncmp(yymsp[0].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5511 +    char *env;
5512 +
5513 +    if (NULL != (env = getenv(yymsp[0].minor.yy43->ptr + 4))) {
5514 +      data_string *ds;
5515 +      ds = data_string_init();
5516 +      buffer_append_string(ds->value, env);
5517 +      yygotominor.yy41 = (data_unset *)ds;
5518 +    }
5519 +    else {
5520 +      yygotominor.yy41 = NULL;
5521 +      fprintf(stderr, "Undefined env variable: %s\n", yymsp[0].minor.yy43->ptr + 4);
5522 +      ctx->ok = 0;
5523 +    }
5524 +  } else if (NULL == (yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43))) {
5525 +    fprintf(stderr, "Undefined config variable: %s\n", yymsp[0].minor.yy43->ptr);
5526 +    ctx->ok = 0;
5527 +  }
5528    if (!yygotominor.yy41) {
5529      /* make a dummy so it won't crash */
5530      yygotominor.yy41 = (data_unset *)data_string_init();
5531 @@ -954,50 +966,59 @@
5532    buffer_free(yymsp[0].minor.yy43);
5533    yymsp[0].minor.yy43 = NULL;
5534  }
5535 -#line 957 "configparser.c"
5536 +#line 969 "configparser.c"
5537          break;
5538        case 15:
5539 -#line 251 "./configparser.y"
5540 +#line 260 "./configparser.y"
5541  {
5542    yygotominor.yy41 = (data_unset *)data_string_init();
5543    buffer_copy_string_buffer(((data_string *)(yygotominor.yy41))->value, yymsp[0].minor.yy0);
5544    buffer_free(yymsp[0].minor.yy0);
5545    yymsp[0].minor.yy0 = NULL;
5546  }
5547 -#line 967 "configparser.c"
5548 +#line 979 "configparser.c"
5549          break;
5550        case 16:
5551 -#line 258 "./configparser.y"
5552 +#line 267 "./configparser.y"
5553  {
5554    yygotominor.yy41 = (data_unset *)data_integer_init();
5555    ((data_integer *)(yygotominor.yy41))->value = strtol(yymsp[0].minor.yy0->ptr, NULL, 10);
5556    buffer_free(yymsp[0].minor.yy0);
5557    yymsp[0].minor.yy0 = NULL;
5558  }
5559 -#line 977 "configparser.c"
5560 +#line 989 "configparser.c"
5561          break;
5562        case 17:
5563 -#line 264 "./configparser.y"
5564 +#line 273 "./configparser.y"
5565  {
5566    yygotominor.yy41 = (data_unset *)data_array_init();
5567    array_free(((data_array *)(yygotominor.yy41))->value);
5568    ((data_array *)(yygotominor.yy41))->value = yymsp[0].minor.yy40;
5569    yymsp[0].minor.yy40 = NULL;
5570  }
5571 -#line 987 "configparser.c"
5572 +#line 999 "configparser.c"
5573          break;
5574        case 18:
5575 -#line 270 "./configparser.y"
5576 +#line 279 "./configparser.y"
5577 +{
5578 +  yygotominor.yy40 = array_init();
5579 +}
5580 +#line 1006 "configparser.c"
5581 +  yy_destructor(8,&yymsp[-1].minor);
5582 +  yy_destructor(9,&yymsp[0].minor);
5583 +        break;
5584 +      case 19:
5585 +#line 282 "./configparser.y"
5586  {
5587    yygotominor.yy40 = yymsp[-1].minor.yy40;
5588    yymsp[-1].minor.yy40 = NULL;
5589  }
5590 -#line 995 "configparser.c"
5591 +#line 1016 "configparser.c"
5592    yy_destructor(8,&yymsp[-2].minor);
5593    yy_destructor(9,&yymsp[0].minor);
5594          break;
5595 -      case 19:
5596 -#line 275 "./configparser.y"
5597 +      case 20:
5598 +#line 287 "./configparser.y"
5599  {
5600    if (buffer_is_empty(yymsp[0].minor.yy41->key) ||
5601        NULL == array_get_element(yymsp[-2].minor.yy40, yymsp[0].minor.yy41->key->ptr)) {
5602 @@ -1014,37 +1035,37 @@
5603    yygotominor.yy40 = yymsp[-2].minor.yy40;
5604    yymsp[-2].minor.yy40 = NULL;
5605  }
5606 -#line 1017 "configparser.c"
5607 +#line 1038 "configparser.c"
5608    yy_destructor(10,&yymsp[-1].minor);
5609          break;
5610 -      case 20:
5611 -#line 292 "./configparser.y"
5612 +      case 21:
5613 +#line 304 "./configparser.y"
5614  {
5615    yygotominor.yy40 = yymsp[-1].minor.yy40;
5616    yymsp[-1].minor.yy40 = NULL;
5617  }
5618 -#line 1026 "configparser.c"
5619 +#line 1047 "configparser.c"
5620    yy_destructor(10,&yymsp[0].minor);
5621          break;
5622 -      case 21:
5623 -#line 297 "./configparser.y"
5624 +      case 22:
5625 +#line 309 "./configparser.y"
5626  {
5627    yygotominor.yy40 = array_init();
5628    array_insert_unique(yygotominor.yy40, yymsp[0].minor.yy41);
5629    yymsp[0].minor.yy41 = NULL;
5630  }
5631 -#line 1036 "configparser.c"
5632 +#line 1057 "configparser.c"
5633          break;
5634 -      case 22:
5635 -#line 303 "./configparser.y"
5636 +      case 23:
5637 +#line 315 "./configparser.y"
5638  {
5639    yygotominor.yy41 = yymsp[0].minor.yy41;
5640    yymsp[0].minor.yy41 = NULL;
5641  }
5642 -#line 1044 "configparser.c"
5643 +#line 1065 "configparser.c"
5644          break;
5645 -      case 23:
5646 -#line 307 "./configparser.y"
5647 +      case 24:
5648 +#line 319 "./configparser.y"
5649  {
5650    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5651    buffer_free(yymsp[-2].minor.yy43);
5652 @@ -1053,27 +1074,27 @@
5653    yygotominor.yy41 = yymsp[0].minor.yy41;
5654    yymsp[0].minor.yy41 = NULL;
5655  }
5656 -#line 1056 "configparser.c"
5657 +#line 1077 "configparser.c"
5658    yy_destructor(11,&yymsp[-1].minor);
5659          break;
5660 -      case 24:
5661 -  yy_destructor(1,&yymsp[0].minor);
5662 -        break;
5663        case 25:
5664 +  yy_destructor(1,&yymsp[0].minor);
5665          break;
5666        case 26:
5667 -#line 319 "./configparser.y"
5668 +        break;
5669 +      case 27:
5670 +#line 331 "./configparser.y"
5671  {
5672    data_config *dc;
5673    dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
5674    assert(dc);
5675    configparser_push(ctx, dc, 0);
5676  }
5677 -#line 1072 "configparser.c"
5678 +#line 1093 "configparser.c"
5679    yy_destructor(12,&yymsp[0].minor);
5680          break;
5681 -      case 27:
5682 -#line 326 "./configparser.y"
5683 +      case 28:
5684 +#line 338 "./configparser.y"
5685  {
5686    data_config *cur;
5687    
5688 @@ -1082,16 +1103,16 @@
5689  
5690    assert(cur && ctx->current);
5691  
5692 -  yygotominor.yy0 = cur;
5693 +  yygotominor.yy78 = cur;
5694  }
5695 -#line 1087 "configparser.c"
5696 +#line 1108 "configparser.c"
5697          /* No destructor defined for globalstart */
5698    yy_destructor(13,&yymsp[-2].minor);
5699          /* No destructor defined for metalines */
5700    yy_destructor(14,&yymsp[0].minor);
5701          break;
5702 -      case 28:
5703 -#line 337 "./configparser.y"
5704 +      case 29:
5705 +#line 349 "./configparser.y"
5706  {
5707    assert(yymsp[-3].minor.yy78->context_ndx < yymsp[0].minor.yy78->context_ndx);
5708    yymsp[0].minor.yy78->prev = yymsp[-3].minor.yy78;
5709 @@ -1100,20 +1121,20 @@
5710    yymsp[-3].minor.yy78 = NULL;
5711    yymsp[0].minor.yy78 = NULL;
5712  }
5713 -#line 1103 "configparser.c"
5714 +#line 1124 "configparser.c"
5715          /* No destructor defined for eols */
5716    yy_destructor(15,&yymsp[-1].minor);
5717          break;
5718 -      case 29:
5719 -#line 346 "./configparser.y"
5720 +      case 30:
5721 +#line 358 "./configparser.y"
5722  {
5723    yygotominor.yy78 = yymsp[0].minor.yy78;
5724    yymsp[0].minor.yy78 = NULL;
5725  }
5726 -#line 1113 "configparser.c"
5727 +#line 1134 "configparser.c"
5728          break;
5729 -      case 30:
5730 -#line 351 "./configparser.y"
5731 +      case 31:
5732 +#line 363 "./configparser.y"
5733  {
5734    data_config *cur;
5735    
5736 @@ -1124,14 +1145,14 @@
5737  
5738    yygotominor.yy78 = cur;
5739  }
5740 -#line 1127 "configparser.c"
5741 +#line 1148 "configparser.c"
5742          /* No destructor defined for context */
5743    yy_destructor(13,&yymsp[-2].minor);
5744          /* No destructor defined for metalines */
5745    yy_destructor(14,&yymsp[0].minor);
5746          break;
5747 -      case 31:
5748 -#line 362 "./configparser.y"
5749 +      case 32:
5750 +#line 374 "./configparser.y"
5751  {
5752    data_config *dc;
5753    buffer *b, *rvalue, *op;
5754 @@ -1266,45 +1287,45 @@
5755    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5756    yymsp[0].minor.yy41 = NULL;
5757  }
5758 -#line 1269 "configparser.c"
5759 +#line 1290 "configparser.c"
5760    yy_destructor(16,&yymsp[-6].minor);
5761    yy_destructor(18,&yymsp[-4].minor);
5762    yy_destructor(19,&yymsp[-2].minor);
5763          break;
5764 -      case 32:
5765 -#line 496 "./configparser.y"
5766 +      case 33:
5767 +#line 508 "./configparser.y"
5768  {
5769    yygotominor.yy27 = CONFIG_COND_EQ;
5770  }
5771 -#line 1279 "configparser.c"
5772 +#line 1300 "configparser.c"
5773    yy_destructor(20,&yymsp[0].minor);
5774          break;
5775 -      case 33:
5776 -#line 499 "./configparser.y"
5777 +      case 34:
5778 +#line 511 "./configparser.y"
5779  {
5780    yygotominor.yy27 = CONFIG_COND_MATCH;
5781  }
5782 -#line 1287 "configparser.c"
5783 +#line 1308 "configparser.c"
5784    yy_destructor(21,&yymsp[0].minor);
5785          break;
5786 -      case 34:
5787 -#line 502 "./configparser.y"
5788 +      case 35:
5789 +#line 514 "./configparser.y"
5790  {
5791    yygotominor.yy27 = CONFIG_COND_NE;
5792  }
5793 -#line 1295 "configparser.c"
5794 +#line 1316 "configparser.c"
5795    yy_destructor(22,&yymsp[0].minor);
5796          break;
5797 -      case 35:
5798 -#line 505 "./configparser.y"
5799 +      case 36:
5800 +#line 517 "./configparser.y"
5801  {
5802    yygotominor.yy27 = CONFIG_COND_NOMATCH;
5803  }
5804 -#line 1303 "configparser.c"
5805 +#line 1324 "configparser.c"
5806    yy_destructor(23,&yymsp[0].minor);
5807          break;
5808 -      case 36:
5809 -#line 509 "./configparser.y"
5810 +      case 37:
5811 +#line 521 "./configparser.y"
5812  {
5813    yygotominor.yy43 = NULL;
5814    if (ctx->ok) {
5815 @@ -1321,10 +1342,10 @@
5816    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5817    yymsp[0].minor.yy41 = NULL;
5818  }
5819 -#line 1324 "configparser.c"
5820 +#line 1345 "configparser.c"
5821          break;
5822 -      case 37:
5823 -#line 526 "./configparser.y"
5824 +      case 38:
5825 +#line 538 "./configparser.y"
5826  {
5827    if (ctx->ok) {
5828      if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
5829 @@ -1334,11 +1355,11 @@
5830      yymsp[0].minor.yy43 = NULL;
5831    }
5832  }
5833 -#line 1337 "configparser.c"
5834 +#line 1358 "configparser.c"
5835    yy_destructor(24,&yymsp[-1].minor);
5836          break;
5837 -      case 38:
5838 -#line 536 "./configparser.y"
5839 +      case 39:
5840 +#line 548 "./configparser.y"
5841  {
5842    if (ctx->ok) {
5843      if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
5844 @@ -1348,7 +1369,7 @@
5845      yymsp[0].minor.yy43 = NULL;
5846    }
5847  }
5848 -#line 1351 "configparser.c"
5849 +#line 1372 "configparser.c"
5850    yy_destructor(25,&yymsp[-1].minor);
5851          break;
5852    };
5853 @@ -1378,11 +1399,11 @@
5854    while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
5855    /* Here code is inserted which will be executed whenever the
5856    ** parser fails */
5857 -#line 125 "./configparser.y"
5858 +#line 107 "./configparser.y"
5859  
5860    ctx->ok = 0;
5861  
5862 -#line 1385 "configparser.c"
5863 +#line 1406 "configparser.c"
5864    configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
5865  }
5866  
5867 @@ -1489,7 +1510,7 @@
5868  #ifdef YYERRORSYMBOL
5869        /* A syntax error has occurred.
5870        ** The response to an error depends upon whether or not the
5871 -      ** grammar defines an error token "ERROR".  
5872 +      ** grammar defines an error token "ERROR".
5873        **
5874        ** This is what we do if the grammar does define ERROR:
5875        **
5876 --- ../lighttpd-1.4.11/src/configparser.y       2006-01-26 18:46:25.000000000 +0200
5877 +++ lighttpd-1.4.12/src/configparser.y  2006-07-16 00:26:04.000000000 +0300
5878 @@ -21,52 +21,34 @@
5879      dc->parent = ctx->current;
5880      array_insert_unique(dc->parent->childs, (data_unset *)dc);
5881    }
5882 -  array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
5883 +  buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
5884    ctx->current = dc;
5885  }
5886  
5887  static data_config *configparser_pop(config_t *ctx) {
5888    data_config *old = ctx->current;
5889 -  ctx->current = (data_config *) array_pop(ctx->configs_stack);
5890 +  ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
5891    return old;
5892  }
5893  
5894  /* return a copied variable */
5895  static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
5896 -  if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
5897 -    char *env;
5898 -
5899 -    if (NULL != (env = getenv(key->ptr + 4))) {
5900 -      data_string *ds;
5901 -      ds = data_string_init();
5902 -      buffer_append_string(ds->value, env);
5903 -      return (data_unset *)ds;
5904 -    }
5905 -
5906 -    fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
5907 -    ctx->ok = 0;
5908 -
5909 -    return NULL;
5910 -  } else {
5911 -    data_unset *du;
5912 -    data_config *dc;
5913 +  data_unset *du;
5914 +  data_config *dc;
5915  
5916  #if 0
5917 -    fprintf(stderr, "get var %s\n", key->ptr);
5918 +  fprintf(stderr, "get var %s\n", key->ptr);
5919  #endif
5920 -    for (dc = ctx->current; dc; dc = dc->parent) {
5921 +  for (dc = ctx->current; dc; dc = dc->parent) {
5922  #if 0
5923 -      fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5924 -      array_print(dc->value, 0);
5925 +    fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5926 +    array_print(dc->value, 0);
5927  #endif
5928 -      if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5929 -        return du->copy(du);
5930 -      }
5931 +    if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5932 +      return du->copy(du);
5933      }
5934 -    fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
5935 -    ctx->ok = 0;
5936 -    return NULL;
5937    }
5938 +  return NULL;
5939  }
5940  
5941  /* op1 is to be eat/return by this function, op1->key is not cared
5942 @@ -141,6 +123,7 @@
5943  %type       aelement               {data_unset *}
5944  %type       condline               {data_config *}
5945  %type       condlines              {data_config *}
5946 +%type       global                 {data_config *}
5947  %type       aelements              {array *}
5948  %type       array                  {array *}
5949  %type       key                    {buffer *}
5950 @@ -161,7 +144,12 @@
5951  
5952  varline ::= key(A) ASSIGN expression(B). {
5953    buffer_copy_string_buffer(B->key, A);
5954 -  if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
5955 +  if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
5956 +    fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
5957 +        ctx->current->context_ndx,
5958 +        ctx->current->key->ptr, A->ptr);
5959 +    ctx->ok = 0;
5960 +  } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
5961      array_insert_unique(ctx->current->value, B);
5962      B = NULL;
5963    } else {
5964 @@ -180,7 +168,12 @@
5965    array *vars = ctx->current->value;
5966    data_unset *du;
5967  
5968 -  if (NULL != (du = array_get_element(vars, A->ptr))) {
5969 +  if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
5970 +    fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
5971 +        ctx->current->context_ndx,
5972 +        ctx->current->key->ptr, A->ptr);
5973 +    ctx->ok = 0;
5974 +  } else if (NULL != (du = array_get_element(vars, A->ptr))) {
5975      /* exists in current block */
5976      du = configparser_merge_data(du, B);
5977      if (NULL == du) {
5978 @@ -190,6 +183,7 @@
5979        buffer_copy_string_buffer(du->key, A);
5980        array_replace(vars, du);
5981      }
5982 +    B->free(B);
5983    } else if (NULL != (du = configparser_get_variable(ctx, A))) {
5984      du = configparser_merge_data(du, B);
5985      if (NULL == du) {
5986 @@ -199,15 +193,13 @@
5987        buffer_copy_string_buffer(du->key, A);
5988        array_insert_unique(ctx->current->value, du);
5989      }
5990 +    B->free(B);
5991    } else {
5992 -    fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n", 
5993 -            ctx->current->context_ndx,
5994 -            ctx->current->key->ptr, A->ptr);
5995 -    ctx->ok = 0;
5996 +    buffer_copy_string_buffer(B->key, A);
5997 +    array_insert_unique(ctx->current->value, B);
5998    }
5999    buffer_free(A);
6000    A = NULL;
6001 -  B->free(B);
6002    B = NULL;
6003  }
6004  
6005 @@ -239,7 +231,24 @@
6006  }
6007  
6008  value(A) ::= key(B). {
6009 -  A = configparser_get_variable(ctx, B);
6010 +  if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
6011 +    char *env;
6012 +
6013 +    if (NULL != (env = getenv(B->ptr + 4))) {
6014 +      data_string *ds;
6015 +      ds = data_string_init();
6016 +      buffer_append_string(ds->value, env);
6017 +      A = (data_unset *)ds;
6018 +    }
6019 +    else {
6020 +      A = NULL;
6021 +      fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
6022 +      ctx->ok = 0;
6023 +    }
6024 +  } else if (NULL == (A = configparser_get_variable(ctx, B))) {
6025 +    fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
6026 +    ctx->ok = 0;
6027 +  }
6028    if (!A) {
6029      /* make a dummy so it won't crash */
6030      A = (data_unset *)data_string_init();
6031 @@ -267,6 +276,9 @@
6032    ((data_array *)(A))->value = B;
6033    B = NULL;
6034  }
6035 +array(A) ::= LPARAN RPARAN. {
6036 +  A = array_init();
6037 +}
6038  array(A) ::= LPARAN aelements(B) RPARAN. {
6039    A = B;
6040    B = NULL;
6041 --- ../lighttpd-1.4.11/src/connections-glue.c   2005-09-12 10:04:23.000000000 +0300
6042 +++ lighttpd-1.4.12/src/connections-glue.c      2006-07-16 00:26:03.000000000 +0300
6043 @@ -13,7 +13,7 @@
6044         case CON_STATE_REQUEST_END: return "req-end";
6045         case CON_STATE_RESPONSE_START: return "resp-start";
6046         case CON_STATE_RESPONSE_END: return "resp-end";
6047 -       default: return "(unknown)";    
6048 +       default: return "(unknown)";
6049         }
6050  }
6051  
6052 @@ -30,15 +30,15 @@
6053         case CON_STATE_REQUEST_END: return "Q";
6054         case CON_STATE_RESPONSE_START: return "s";
6055         case CON_STATE_RESPONSE_END: return "S";
6056 -       default: return "x";    
6057 +       default: return "x";
6058         }
6059  }
6060  
6061  int connection_set_state(server *srv, connection *con, connection_state_t state) {
6062         UNUSED(srv);
6063 -       
6064 +
6065         con->state = state;
6066 -       
6067 +
6068         return 0;
6069  }
6070  
6071 --- ../lighttpd-1.4.11/src/connections.c        2006-03-05 22:14:53.000000000 +0200
6072 +++ lighttpd-1.4.12/src/connections.c   2006-07-18 13:03:40.000000000 +0300
6073 @@ -2,7 +2,6 @@
6074  
6075  #include <stdlib.h>
6076  #include <stdio.h>
6077 -#include <unistd.h>
6078  #include <errno.h>
6079  #include <string.h>
6080  #include <fcntl.h>
6081 @@ -26,8 +25,8 @@
6082  #include "inet_ntop_cache.h"
6083  
6084  #ifdef USE_OPENSSL
6085 -# include <openssl/ssl.h> 
6086 -# include <openssl/err.h> 
6087 +# include <openssl/ssl.h>
6088 +# include <openssl/err.h>
6089  #endif
6090  
6091  #ifdef HAVE_SYS_FILIO_H
6092 @@ -35,15 +34,16 @@
6093  #endif
6094  
6095  #include "sys-socket.h"
6096 +#include "sys-files.h"
6097  
6098  typedef struct {
6099 -               PLUGIN_DATA;
6100 +       PLUGIN_DATA;
6101  } plugin_data;
6102  
6103  static connection *connections_get_new_connection(server *srv) {
6104         connections *conns = srv->conns;
6105         size_t i;
6106 -       
6107 +
6108         if (conns->size == 0) {
6109                 conns->size = 128;
6110                 conns->ptr = NULL;
6111 @@ -54,21 +54,14 @@
6112         } else if (conns->size == conns->used) {
6113                 conns->size += 128;
6114                 conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size);
6115 -               
6116 +
6117                 for (i = conns->used; i < conns->size; i++) {
6118                         conns->ptr[i] = connection_init(srv);
6119                 }
6120         }
6121  
6122         connection_reset(srv, conns->ptr[conns->used]);
6123 -#if 0  
6124 -       fprintf(stderr, "%s.%d: add: ", __FILE__, __LINE__);
6125 -       for (i = 0; i < conns->used + 1; i++) {
6126 -               fprintf(stderr, "%d ", conns->ptr[i]->fd);
6127 -       }
6128 -       fprintf(stderr, "\n");
6129 -#endif 
6130 -       
6131 +
6132         conns->ptr[conns->used]->ndx = conns->used;
6133         return conns->ptr[conns->used++];
6134  }
6135 @@ -77,263 +70,134 @@
6136         size_t i;
6137         connections *conns = srv->conns;
6138         connection *temp;
6139 -       
6140 +
6141         if (con == NULL) return -1;
6142 -       
6143 +
6144         if (-1 == con->ndx) return -1;
6145 -       
6146 +
6147         i = con->ndx;
6148 -       
6149 +
6150         /* not last element */
6151 -       
6152 +
6153         if (i != conns->used - 1) {
6154                 temp = conns->ptr[i];
6155                 conns->ptr[i] = conns->ptr[conns->used - 1];
6156                 conns->ptr[conns->used - 1] = temp;
6157 -               
6158 +
6159                 conns->ptr[i]->ndx = i;
6160                 conns->ptr[conns->used - 1]->ndx = -1;
6161         }
6162 -       
6163 +
6164         conns->used--;
6165 -       
6166 +
6167         con->ndx = -1;
6168 -#if 0
6169 -       fprintf(stderr, "%s.%d: del: (%d)", __FILE__, __LINE__, conns->used);
6170 -       for (i = 0; i < conns->used; i++) {
6171 -               fprintf(stderr, "%d ", conns->ptr[i]->fd);
6172 -       }
6173 -       fprintf(stderr, "\n");
6174 -#endif 
6175 +
6176         return 0;
6177  }
6178  
6179  int connection_close(server *srv, connection *con) {
6180  #ifdef USE_OPENSSL
6181         server_socket *srv_sock = con->srv_socket;
6182 -#endif
6183 -       
6184 -#ifdef USE_OPENSSL
6185 +
6186         if (srv_sock->is_ssl) {
6187 -               if (con->ssl) SSL_free(con->ssl);
6188 -               con->ssl = NULL;
6189 +               if (con->sock->ssl) SSL_free(con->sock->ssl);
6190 +               con->sock->ssl = NULL;
6191         }
6192  #endif
6193 -       
6194 -       fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
6195 -       fdevent_unregister(srv->ev, con->fd);
6196 -#ifdef __WIN32
6197 -       if (closesocket(con->fd)) {
6198 -               log_error_write(srv, __FILE__, __LINE__, "sds",
6199 -                               "(warning) close:", con->fd, strerror(errno));
6200 -       }
6201 -#else
6202 -       if (close(con->fd)) {
6203 +
6204 +       fdevent_event_del(srv->ev, con->sock);
6205 +       fdevent_unregister(srv->ev, con->sock);
6206 +
6207 +       if (closesocket(con->sock->fd)) {
6208                 log_error_write(srv, __FILE__, __LINE__, "sds",
6209 -                               "(warning) close:", con->fd, strerror(errno));
6210 +                               "(warning) close:", con->sock->fd, strerror(errno));
6211         }
6212 -#endif
6213 -       
6214 +
6215         srv->cur_fds--;
6216 -#if 0
6217 -       log_error_write(srv, __FILE__, __LINE__, "sd",
6218 -                       "closed()", con->fd);
6219 -#endif
6220 -       
6221 +
6222         connection_del(srv, con);
6223         connection_set_state(srv, con, CON_STATE_CONNECT);
6224 -       
6225 +
6226         return 0;
6227  }
6228  
6229  #if 0
6230  static void dump_packet(const unsigned char *data, size_t len) {
6231         size_t i, j;
6232 -       
6233 +
6234         if (len == 0) return;
6235 -       
6236 +
6237         for (i = 0; i < len; i++) {
6238                 if (i % 16 == 0) fprintf(stderr, "  ");
6239 -               
6240 +
6241                 fprintf(stderr, "%02x ", data[i]);
6242 -               
6243 +
6244                 if ((i + 1) % 16 == 0) {
6245                         fprintf(stderr, "  ");
6246                         for (j = 0; j <= i % 16; j++) {
6247                                 unsigned char c;
6248 -                               
6249 +
6250                                 if (i-15+j >= len) break;
6251 -                               
6252 +
6253                                 c = data[i-15+j];
6254 -                               
6255 +
6256                                 fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6257                         }
6258 -                       
6259 +
6260                         fprintf(stderr, "\n");
6261                 }
6262         }
6263 -       
6264 +
6265         if (len % 16 != 0) {
6266                 for (j = i % 16; j < 16; j++) {
6267                         fprintf(stderr, "   ");
6268                 }
6269 -               
6270 +
6271                 fprintf(stderr, "  ");
6272                 for (j = i & ~0xf; j < len; j++) {
6273                         unsigned char c;
6274 -                       
6275 +
6276                         c = data[j];
6277                         fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6278                 }
6279                 fprintf(stderr, "\n");
6280         }
6281  }
6282 -#endif 
6283 -
6284 -static int connection_handle_read(server *srv, connection *con) {
6285 -       int len;
6286 -       buffer *b;
6287 -       int toread;
6288 -#ifdef USE_OPENSSL
6289 -       server_socket *srv_sock = con->srv_socket;
6290  #endif
6291  
6292 -       b = chunkqueue_get_append_buffer(con->read_queue);
6293 -       buffer_prepare_copy(b, 4096);
6294 -
6295 -#ifdef USE_OPENSSL
6296 -       if (srv_sock->is_ssl) {
6297 -               len = SSL_read(con->ssl, b->ptr, b->size - 1);
6298 -       } else {
6299 -               if (ioctl(con->fd, FIONREAD, &toread)) {
6300 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
6301 -                                       "unexpected end-of-file:",
6302 -                                       con->fd);
6303 -                       return -1;
6304 -               }
6305 -               buffer_prepare_copy(b, toread);
6306 +static network_status_t connection_handle_read(server *srv, connection *con) {
6307 +       off_t oldlen, newlen;
6308  
6309 -               len = read(con->fd, b->ptr, b->size - 1);
6310 -       }
6311 -#elif defined(__WIN32)
6312 -       len = recv(con->fd, b->ptr, b->size - 1, 0);
6313 -#else
6314 -       if (ioctl(con->fd, FIONREAD, &toread)) {
6315 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
6316 -                               "unexpected end-of-file:",
6317 -                               con->fd);
6318 -               return -1;
6319 -       }
6320 -       buffer_prepare_copy(b, toread);
6321 +       oldlen = chunkqueue_length(con->read_queue);
6322  
6323 -       len = read(con->fd, b->ptr, b->size - 1);
6324 -#endif
6325 -       
6326 -       if (len < 0) {
6327 +       switch(network_read_chunkqueue(srv, con, con->read_queue)) {
6328 +       case NETWORK_STATUS_SUCCESS:
6329 +               break;
6330 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
6331 +               con->is_readable = 0;
6332 +               return NETWORK_STATUS_WAIT_FOR_EVENT;
6333 +       case NETWORK_STATUS_INTERRUPTED:
6334 +               con->is_readable = 1;
6335 +               return NETWORK_STATUS_WAIT_FOR_EVENT;
6336 +       case NETWORK_STATUS_CONNECTION_CLOSE:
6337 +               /* pipelining */
6338 +               con->is_readable = 0;
6339 +               return NETWORK_STATUS_CONNECTION_CLOSE;
6340 +       case NETWORK_STATUS_FATAL_ERROR:
6341                 con->is_readable = 0;
6342 -               
6343 -#ifdef USE_OPENSSL
6344 -               if (srv_sock->is_ssl) {
6345 -                       int r, ssl_err;
6346 -                       
6347 -                       switch ((r = SSL_get_error(con->ssl, len))) {
6348 -                       case SSL_ERROR_WANT_READ:
6349 -                               return 0;
6350 -                       case SSL_ERROR_SYSCALL:
6351 -                               /**
6352 -                                * man SSL_get_error()
6353 -                                * 
6354 -                                * SSL_ERROR_SYSCALL
6355 -                                *   Some I/O error occurred.  The OpenSSL error queue may contain more 
6356 -                                *   information on the error.  If the error queue is empty (i.e.
6357 -                                *   ERR_get_error() returns 0), ret can be used to find out more about 
6358 -                                *   the error: If ret == 0, an EOF was observed that violates the
6359 -                                *   protocol.  If ret == -1, the underlying BIO reported an I/O error 
6360 -                                *   (for socket I/O on Unix systems, consult errno for details).
6361 -                                *
6362 -                                */
6363 -                               while((ssl_err = ERR_get_error())) {
6364 -                                       /* get all errors from the error-queue */
6365 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", 
6366 -                                                       r, ERR_error_string(ssl_err, NULL));
6367 -                               }
6368  
6369 -                               switch(errno) {
6370 -                               default:
6371 -                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", 
6372 -                                                       len, r, errno,
6373 -                                                       strerror(errno));
6374 -                                       break;
6375 -                               }
6376 -                               
6377 -                               break;
6378 -                       case SSL_ERROR_ZERO_RETURN:
6379 -                               /* clean shutdown on the remote side */
6380 -                               
6381 -                               if (r == 0) {
6382 -                                       /* FIXME: later */
6383 -                               }
6384 -                               
6385 -                               /* fall thourgh */
6386 -                       default:
6387 -                               while((ssl_err = ERR_get_error())) {
6388 -                                       /* get all errors from the error-queue */
6389 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", 
6390 -                                                       r, ERR_error_string(ssl_err, NULL));
6391 -                               }
6392 -                               break;
6393 -                       }
6394 -               } else {
6395 -                       if (errno == EAGAIN) return 0;
6396 -                       if (errno == EINTR) {
6397 -                               /* we have been interrupted before we could read */
6398 -                               con->is_readable = 1;
6399 -                               return 0;
6400 -                       }
6401 -               
6402 -                       if (errno != ECONNRESET) {
6403 -                               /* expected for keep-alive */
6404 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6405 -                       }
6406 -               }
6407 -#else
6408 -               if (errno == EAGAIN) return 0;
6409 -               if (errno == EINTR) {
6410 -                       /* we have been interrupted before we could read */
6411 -                       con->is_readable = 1;
6412 -                       return 0;
6413 -               }
6414 -               
6415 -               if (errno != ECONNRESET) {
6416 -                       /* expected for keep-alive */
6417 -                       log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6418 -               }
6419 -#endif
6420                 connection_set_state(srv, con, CON_STATE_ERROR);
6421 -               
6422 -               return -1;
6423 -       } else if (len == 0) {
6424 -               con->is_readable = 0;
6425 -               /* the other end close the connection -> KEEP-ALIVE */
6426 +               return NETWORK_STATUS_FATAL_ERROR;
6427 +       default:
6428 +               SEGFAULT();
6429 +               break;
6430 +       }
6431  
6432 -               /* pipelining */
6433 +       newlen = chunkqueue_length(con->read_queue);
6434  
6435 -               return -2;
6436 -       } else if ((size_t)len < b->size - 1) {
6437 -               /* we got less then expected, wait for the next fd-event */
6438 -               
6439 -               con->is_readable = 0;
6440 -       }
6441 -       
6442 -       b->used = len;
6443 -       b->ptr[b->used++] = '\0';
6444 -       
6445 -       con->bytes_read += len;
6446 -#if 0
6447 -       dump_packet(b->ptr, len);
6448 -#endif
6449 -       
6450 -       return 0;
6451 +       con->bytes_read += (newlen - oldlen);
6452 +
6453 +       return NETWORK_STATUS_SUCCESS;
6454  }
6455  
6456  static int connection_handle_write_prepare(server *srv, connection *con) {
6457 @@ -343,6 +207,7 @@
6458                 case HTTP_METHOD_GET:
6459                 case HTTP_METHOD_POST:
6460                 case HTTP_METHOD_HEAD:
6461 +                       /* webdav */
6462                 case HTTP_METHOD_PUT:
6463                 case HTTP_METHOD_MKCOL:
6464                 case HTTP_METHOD_DELETE:
6465 @@ -350,12 +215,14 @@
6466                 case HTTP_METHOD_MOVE:
6467                 case HTTP_METHOD_PROPFIND:
6468                 case HTTP_METHOD_PROPPATCH:
6469 +               case HTTP_METHOD_LOCK:
6470 +               case HTTP_METHOD_UNLOCK:
6471                         break;
6472                 case HTTP_METHOD_OPTIONS:
6473                         /*
6474                          * 400 is coming from the request-parser BEFORE uri.path is set
6475 -                        * 403 is from the response handler when noone else catched it 
6476 -                        * 
6477 +                        * 403 is from the response handler when noone else catched it
6478 +                        *
6479                          * */
6480                         if (con->uri.path->used &&
6481                             con->uri.path->ptr[0] != '*') {
6482 @@ -381,55 +248,60 @@
6483                         break;
6484                 }
6485         }
6486 -       
6487 +
6488         if (con->http_status == 0) {
6489                 con->http_status = 403;
6490         }
6491 -       
6492 +
6493         switch(con->http_status) {
6494         case 400: /* class: header + custom body */
6495         case 401:
6496         case 403:
6497         case 404:
6498         case 408:
6499 +       case 409:
6500 +       case 410:
6501         case 411:
6502         case 416:
6503         case 423:
6504         case 500:
6505         case 501:
6506 +       case 502:
6507         case 503:
6508 -       case 505: 
6509 +       case 504:
6510 +       case 505:
6511 +       case 509:
6512                 if (con->mode != DIRECT) break;
6513 -               
6514 +
6515                 con->file_finished = 0;
6516 -               
6517 +
6518                 buffer_reset(con->physical.path);
6519 -                               
6520 +
6521                 /* try to send static errorfile */
6522                 if (!buffer_is_empty(con->conf.errorfile_prefix)) {
6523                         stat_cache_entry *sce = NULL;
6524 -                       
6525 +
6526                         buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix);
6527                         buffer_append_string(con->physical.path, get_http_status_body_name(con->http_status));
6528 -                       
6529 +
6530                         if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
6531                                 con->file_finished = 1;
6532 -                               
6533 +
6534                                 http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
6535                                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
6536                         }
6537                 }
6538 -               
6539 -               if (!con->file_finished) {                      
6540 +
6541 +               if (!con->file_finished) {
6542                         buffer *b;
6543 -                       
6544 +
6545                         buffer_reset(con->physical.path);
6546 -                       
6547 +
6548                         con->file_finished = 1;
6549                         b = chunkqueue_get_append_buffer(con->write_queue);
6550 -                               
6551 +
6552                         /* build default error-page */
6553 -                       buffer_copy_string(b, 
6554 +                       buffer_copy_string(b,
6555                                            "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
6556                                            "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
6557                                            "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
6558 @@ -439,7 +311,7 @@
6559                         buffer_append_long(b, con->http_status);
6560                         buffer_append_string(b, " - ");
6561                         buffer_append_string(b, get_http_status_name(con->http_status));
6562 -                       
6563 +
6564                         buffer_append_string(b,
6565                                              "</title>\n"
6566                                              " </head>\n"
6567 @@ -448,12 +320,12 @@
6568                         buffer_append_long(b, con->http_status);
6569                         buffer_append_string(b, " - ");
6570                         buffer_append_string(b, get_http_status_name(con->http_status));
6571 -                       
6572 -                       buffer_append_string(b,"</h1>\n" 
6573 +
6574 +                       buffer_append_string(b,"</h1>\n"
6575                                              " </body>\n"
6576                                              "</html>\n"
6577                                              );
6578 -                       
6579 +
6580                         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
6581                 }
6582                 /* fall through */
6583 @@ -463,10 +335,10 @@
6584         case 301:
6585         case 302:
6586                 break;
6587 -               
6588 +
6589         case 206: /* write_queue is already prepared */
6590                 con->file_finished = 1;
6591 -               
6592 +
6593                 break;
6594         case 205: /* class: header only */
6595         case 304:
6596 @@ -474,19 +346,19 @@
6597                 /* disable chunked encoding again as we have no body */
6598                 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
6599                 chunkqueue_reset(con->write_queue);
6600 -               
6601 +
6602                 con->file_finished = 1;
6603                 break;
6604         }
6605 -       
6606 +
6607  
6608         if (con->file_finished) {
6609 -               /* we have all the content and chunked encoding is not used, set a content-length */ 
6610 -               
6611 -               if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) && 
6612 +               /* we have all the content and chunked encoding is not used, set a content-length */
6613 +
6614 +               if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) &&
6615                     (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) {
6616                         buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->write_queue));
6617 -               
6618 +
6619                         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
6620                 }
6621         } else {
6622 @@ -495,77 +367,79 @@
6623                     ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) {
6624                         con->keep_alive = 0;
6625                 }
6626 -               
6627 +
6628                 if (0 == (con->parsed_response & HTTP_CONNECTION)) {
6629                         /* (f)cgi did'nt send Connection: header
6630 -                        *                          
6631 +                        *
6632                          * shall we ?
6633                          */
6634                         if (((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) &&
6635                             (con->parsed_response & HTTP_CONTENT_LENGTH) == 0) {
6636                                 /* without content_length, no keep-alive */
6637 -                               
6638 +
6639                                 con->keep_alive = 0;
6640                         }
6641                 } else {
6642                         /* a subrequest disable keep-alive although the client wanted it */
6643                         if (con->keep_alive && !con->response.keep_alive) {
6644                                 con->keep_alive = 0;
6645 -                               
6646 +
6647                                 /* FIXME: we have to drop the Connection: Header from the subrequest */
6648                         }
6649                 }
6650         }
6651 -       
6652 +
6653         if (con->request.http_method == HTTP_METHOD_HEAD) {
6654                 chunkqueue_reset(con->write_queue);
6655         }
6656  
6657         http_response_write_header(srv, con);
6658 -               
6659 +
6660         return 0;
6661  }
6662  
6663  static int connection_handle_write(server *srv, connection *con) {
6664         switch(network_write_chunkqueue(srv, con, con->write_queue)) {
6665 -       case 0:
6666 +       case NETWORK_STATUS_SUCCESS:
6667                 if (con->file_finished) {
6668                         connection_set_state(srv, con, CON_STATE_RESPONSE_END);
6669                         joblist_append(srv, con);
6670                 }
6671                 break;
6672 -       case -1: /* error on our side */
6673 +       case NETWORK_STATUS_FATAL_ERROR: /* error on our side */
6674                 log_error_write(srv, __FILE__, __LINE__, "sd",
6675 -                               "connection closed: write failed on fd", con->fd);
6676 +                               "connection closed: write failed on fd", con->sock->fd);
6677                 connection_set_state(srv, con, CON_STATE_ERROR);
6678                 joblist_append(srv, con);
6679                 break;
6680 -       case -2: /* remote close */
6681 +       case NETWORK_STATUS_CONNECTION_CLOSE: /* remote close */
6682                 connection_set_state(srv, con, CON_STATE_ERROR);
6683                 joblist_append(srv, con);
6684                 break;
6685 -       case 1:
6686 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
6687                 con->is_writable = 0;
6688 -               
6689 +
6690                 /* not finished yet -> WRITE */
6691                 break;
6692 +       case NETWORK_STATUS_INTERRUPTED:
6693 +               con->is_writable = 1;
6694 +               break;
6695 +       case NETWORK_STATUS_UNSET:
6696 +               break;
6697         }
6698 -       
6699 +
6700         return 0;
6701  }
6702  
6703 -
6704 -
6705  connection *connection_init(server *srv) {
6706         connection *con;
6707 -       
6708 +
6709         UNUSED(srv);
6710  
6711         con = calloc(1, sizeof(*con));
6712 -               
6713 -       con->fd = 0;
6714 +
6715 +       con->sock = iosocket_init();
6716         con->ndx = -1;
6717 -       con->fde_ndx = -1;
6718         con->bytes_written = 0;
6719         con->bytes_read = 0;
6720         con->bytes_header = 0;
6721 @@ -573,32 +447,32 @@
6722  
6723  #define CLEAN(x) \
6724         con->x = buffer_init();
6725 -       
6726 +
6727         CLEAN(request.uri);
6728         CLEAN(request.request_line);
6729         CLEAN(request.request);
6730         CLEAN(request.pathinfo);
6731 -       
6732 +
6733         CLEAN(request.orig_uri);
6734 -       
6735 +
6736         CLEAN(uri.scheme);
6737         CLEAN(uri.authority);
6738         CLEAN(uri.path);
6739         CLEAN(uri.path_raw);
6740         CLEAN(uri.query);
6741 -       
6742 +
6743         CLEAN(physical.doc_root);
6744         CLEAN(physical.path);
6745         CLEAN(physical.basedir);
6746         CLEAN(physical.rel_path);
6747         CLEAN(physical.etag);
6748         CLEAN(parse_request);
6749 -       
6750 +
6751         CLEAN(authed_user);
6752         CLEAN(server_name);
6753         CLEAN(error_handler);
6754         CLEAN(dst_addr_buf);
6755 -       
6756 +
6757  #undef CLEAN
6758         con->write_queue = chunkqueue_init();
6759         con->read_queue = chunkqueue_init();
6760 @@ -608,26 +482,27 @@
6761         con->request.headers      = array_init();
6762         con->response.headers     = array_init();
6763         con->environment     = array_init();
6764 -       
6765 +
6766         /* init plugin specific connection structures */
6767 -       
6768 +
6769         con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
6770 -       
6771 +
6772         con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
6773         config_setup_connection(srv, con);
6774 -       
6775 +
6776         return con;
6777  }
6778  
6779  void connections_free(server *srv) {
6780         connections *conns = srv->conns;
6781 -       size_t i;       
6782 -       
6783 +       size_t i;
6784 +
6785         for (i = 0; i < conns->size; i++) {
6786                 connection *con = conns->ptr[i];
6787 -               
6788 +
6789                 connection_reset(srv, con);
6790 -               
6791 +               iosocket_free(con->sock);
6792 +
6793                 chunkqueue_free(con->write_queue);
6794                 chunkqueue_free(con->read_queue);
6795                 chunkqueue_free(con->request_content_queue);
6796 @@ -637,27 +512,27 @@
6797  
6798  #define CLEAN(x) \
6799         buffer_free(con->x);
6800 -               
6801 +
6802                 CLEAN(request.uri);
6803                 CLEAN(request.request_line);
6804                 CLEAN(request.request);
6805                 CLEAN(request.pathinfo);
6806 -               
6807 +
6808                 CLEAN(request.orig_uri);
6809 -               
6810 +
6811                 CLEAN(uri.scheme);
6812                 CLEAN(uri.authority);
6813                 CLEAN(uri.path);
6814                 CLEAN(uri.path_raw);
6815                 CLEAN(uri.query);
6816 -               
6817 +
6818                 CLEAN(physical.doc_root);
6819                 CLEAN(physical.path);
6820                 CLEAN(physical.basedir);
6821                 CLEAN(physical.etag);
6822                 CLEAN(physical.rel_path);
6823                 CLEAN(parse_request);
6824 -               
6825 +
6826                 CLEAN(authed_user);
6827                 CLEAN(server_name);
6828                 CLEAN(error_handler);
6829 @@ -665,97 +540,97 @@
6830  #undef CLEAN
6831                 free(con->plugin_ctx);
6832                 free(con->cond_cache);
6833 -               
6834 +
6835                 free(con);
6836         }
6837 -       
6838 +
6839         free(conns->ptr);
6840  }
6841  
6842  
6843  int connection_reset(server *srv, connection *con) {
6844         size_t i;
6845 -       
6846 +
6847         plugins_call_connection_reset(srv, con);
6848 -       
6849 +
6850         con->is_readable = 1;
6851         con->is_writable = 1;
6852         con->http_status = 0;
6853         con->file_finished = 0;
6854         con->file_started = 0;
6855         con->got_response = 0;
6856 -       
6857 +
6858         con->parsed_response = 0;
6859 -       
6860 +
6861         con->bytes_written = 0;
6862         con->bytes_written_cur_second = 0;
6863         con->bytes_read = 0;
6864         con->bytes_header = 0;
6865         con->loops_per_request = 0;
6866 -       
6867 +
6868         con->request.http_method = HTTP_METHOD_UNSET;
6869         con->request.http_version = HTTP_VERSION_UNSET;
6870 -       
6871 +
6872         con->request.http_if_modified_since = NULL;
6873         con->request.http_if_none_match = NULL;
6874 -       
6875 +
6876         con->response.keep_alive = 0;
6877         con->response.content_length = -1;
6878         con->response.transfer_encoding = 0;
6879 -       
6880 +
6881         con->mode = DIRECT;
6882 -       
6883 +
6884  #define CLEAN(x) \
6885         if (con->x) buffer_reset(con->x);
6886 -       
6887 +
6888         CLEAN(request.uri);
6889         CLEAN(request.request_line);
6890         CLEAN(request.pathinfo);
6891         CLEAN(request.request);
6892 -       
6893 +
6894         CLEAN(request.orig_uri);
6895 -       
6896 +
6897         CLEAN(uri.scheme);
6898         CLEAN(uri.authority);
6899         CLEAN(uri.path);
6900         CLEAN(uri.path_raw);
6901         CLEAN(uri.query);
6902 -       
6903 +
6904         CLEAN(physical.doc_root);
6905         CLEAN(physical.path);
6906         CLEAN(physical.basedir);
6907         CLEAN(physical.rel_path);
6908         CLEAN(physical.etag);
6909 -       
6910 +
6911         CLEAN(parse_request);
6912 -       
6913 +
6914         CLEAN(authed_user);
6915         CLEAN(server_name);
6916         CLEAN(error_handler);
6917 -#undef CLEAN   
6918 -       
6919 +#undef CLEAN
6920 +
6921  #define CLEAN(x) \
6922 -       if (con->x) con->x->used = 0;   
6923 -       
6924 +       if (con->x) con->x->used = 0;
6925 +
6926  #undef CLEAN
6927 -       
6928 +
6929  #define CLEAN(x) \
6930                 con->request.x = NULL;
6931 -       
6932 +
6933         CLEAN(http_host);
6934         CLEAN(http_range);
6935         CLEAN(http_content_type);
6936  #undef CLEAN
6937         con->request.content_length = 0;
6938 -       
6939 +
6940         array_reset(con->request.headers);
6941         array_reset(con->response.headers);
6942         array_reset(con->environment);
6943 -       
6944 +
6945         chunkqueue_reset(con->write_queue);
6946         chunkqueue_reset(con->request_content_queue);
6947  
6948 -       /* the plugins should cleanup themself */       
6949 +       /* the plugins should cleanup themself */
6950         for (i = 0; i < srv->plugins.used; i++) {
6951                 plugin *p = ((plugin **)(srv->plugins.ptr))[i];
6952                 plugin_data *pd = p->data;
6953 @@ -768,7 +643,7 @@
6954  
6955                 con->plugin_ctx[pd->id] = NULL;
6956         }
6957 -       
6958 +
6959  #if COND_RESULT_UNSET
6960         for (i = srv->config_context->used - 1; i >= 0; i --) {
6961                 con->cond_cache[i].result = COND_RESULT_UNSET;
6962 @@ -777,56 +652,56 @@
6963  #else
6964         memset(con->cond_cache, 0, sizeof(cond_cache_t) * srv->config_context->used);
6965  #endif
6966 -       
6967 +
6968         con->header_len = 0;
6969         con->in_error_handler = 0;
6970 -       
6971 +
6972         config_setup_connection(srv, con);
6973 -       
6974 +
6975         return 0;
6976  }
6977  
6978  /**
6979 - * 
6980 - * search for \r\n\r\n 
6981 - * 
6982 + *
6983 + * search for \r\n\r\n
6984 + *
6985   * this is a special 32bit version which is using a sliding window for
6986 - * the comparisions 
6987 - * 
6988 + * the comparisions
6989 + *
6990   * how it works:
6991 - * 
6992 + *
6993   * b:      'abcdefg'
6994   * rnrn:   'cdef'
6995 - * 
6996 + *
6997   * cmpbuf: abcd != cdef
6998   * cmpbuf: bcde != cdef
6999   * cmpbuf: cdef == cdef -> return &c
7000 - * 
7001 - * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to 
7002 + *
7003 + * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to
7004   * maintain cmpbuf and rnrn
7005 - * 
7006 + *
7007   */
7008  
7009  char *buffer_search_rnrn(buffer *b) {
7010         uint32_t cmpbuf, rnrn;
7011         char *cp;
7012         size_t i;
7013 -       
7014 +
7015         if (b->used < 4) return NULL;
7016 -       
7017 +
7018         rnrn = ('\r' << 24) | ('\n' << 16) |
7019                 ('\r' << 8) | ('\n' << 0);
7020 -       
7021 +
7022         cmpbuf = (b->ptr[0] << 24) | (b->ptr[1] << 16) |
7023                 (b->ptr[2] << 8) | (b->ptr[3] << 0);
7024 -               
7025 +
7026         cp = b->ptr + 4;
7027         for (i = 0; i < b->used - 4; i++) {
7028                 if (cmpbuf == rnrn) return cp - 4;
7029 -                       
7030 +
7031                 cmpbuf = (cmpbuf << 8 | *(cp++)) & 0xffffffff;
7032         }
7033 -       
7034 +
7035         return NULL;
7036  }
7037  /**
7038 @@ -840,22 +715,25 @@
7039         chunk *c;
7040         chunkqueue *cq = con->read_queue;
7041         chunkqueue *dst_cq = con->request_content_queue;
7042 -       
7043 +
7044         if (con->is_readable) {
7045                 con->read_idle_ts = srv->cur_ts;
7046 -       
7047 +
7048                 switch(connection_handle_read(srv, con)) {
7049 -               case -1:
7050 +               case NETWORK_STATUS_FATAL_ERROR:
7051                         return -1;
7052 -               case -2:
7053 +               case NETWORK_STATUS_CONNECTION_CLOSE:
7054                         /* remote side closed the connection
7055                          * if we still have content, handle it, if not leave here */
7056  
7057                         if (cq->first == cq->last &&
7058 -                           cq->first->mem->used == 0) {
7059 +                           (NULL == cq->first ||
7060 +                           cq->first->mem->used == 0)) {
7061  
7062                                 /* conn-closed, leave here */
7063                                 connection_set_state(srv, con, CON_STATE_ERROR);
7064 +
7065 +                               return 0;
7066                         }
7067                 default:
7068                         break;
7069 @@ -891,14 +769,14 @@
7070                         /* the last node was empty */
7071                         if (c->next == NULL) {
7072                                 cq->last = c;
7073 -                       } 
7074 +                       }
7075  
7076                         c = c->next;
7077                 } else {
7078                         c = c->next;
7079                 }
7080         }
7081 -       
7082 +
7083         /* nothing to handle */
7084         if (cq->first == NULL) return 0;
7085  
7086 @@ -906,25 +784,26 @@
7087         case CON_STATE_READ:
7088                 /* prepare con->request.request */
7089                 c = cq->first;
7090 -               
7091 +
7092                 /* check if we need the full package */
7093                 if (con->request.request->used == 0) {
7094                         buffer b;
7095 -                       
7096 +
7097                         b.ptr = c->mem->ptr + c->offset;
7098                         b.used = c->mem->used - c->offset;
7099 -                       
7100 +
7101                         if (NULL != (h_term = buffer_search_rnrn(&b))) {
7102                                 /* \r\n\r\n found
7103                                  * - copy everything incl. the terminator to request.request
7104                                  */
7105 -                               
7106 -                               buffer_copy_string_len(con->request.request, 
7107 -                                                      b.ptr, 
7108 +
7109 +                               buffer_copy_string_len(con->request.request,
7110 +                                                      b.ptr,
7111                                                        h_term - b.ptr + 4);
7112 -                               
7113 +
7114                                 /* the buffer has been read up to the terminator */
7115                                 c->offset += h_term - b.ptr + 4;
7116 +
7117                         } else {
7118                                 /* not found, copy everything */
7119                                 buffer_copy_string_len(con->request.request, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
7120 @@ -932,14 +811,14 @@
7121                         }
7122                 } else {
7123                         /* have to take care of overlapping header terminators */
7124 -                       
7125 +
7126                         size_t l = con->request.request->used - 2;
7127                         char *s  = con->request.request->ptr;
7128                         buffer b;
7129 -                       
7130 +
7131                         b.ptr = c->mem->ptr + c->offset;
7132                         b.used = c->mem->used - c->offset;
7133 -                       
7134 +
7135                         if (con->request.request->used - 1 > 3 &&
7136                             c->mem->used > 1 &&
7137                             s[l-2] == '\r' &&
7138 @@ -948,7 +827,7 @@
7139                             c->mem->ptr[0] == '\n') {
7140                                 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 1);
7141                                 c->offset += 1;
7142 -                               
7143 +
7144                                 h_term = con->request.request->ptr;
7145                         } else if (con->request.request->used - 1 > 2 &&
7146                                    c->mem->used > 2 &&
7147 @@ -958,7 +837,7 @@
7148                                    c->mem->ptr[1] == '\n') {
7149                                 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 2);
7150                                 c->offset += 2;
7151 -                               
7152 +
7153                                 h_term = con->request.request->ptr;
7154                         } else if (con->request.request->used - 1 > 1 &&
7155                                    c->mem->used > 3 &&
7156 @@ -968,17 +847,17 @@
7157                                    c->mem->ptr[2] == '\n') {
7158                                 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 3);
7159                                 c->offset += 3;
7160 -                               
7161 +
7162                                 h_term = con->request.request->ptr;
7163                         } else if (NULL != (h_term = buffer_search_string_len(&b, "\r\n\r\n", 4))) {
7164                                 /* \r\n\r\n found
7165                                  * - copy everything incl. the terminator to request.request
7166                                  */
7167 -                               
7168 -                               buffer_append_string_len(con->request.request, 
7169 -                                                      c->mem->ptr + c->offset, 
7170 +
7171 +                               buffer_append_string_len(con->request.request,
7172 +                                                      c->mem->ptr + c->offset,
7173                                                        c->offset + h_term - b.ptr + 4);
7174 -                               
7175 +
7176                                 /* the buffer has been read up to the terminator */
7177                                 c->offset += h_term - b.ptr + 4;
7178                         } else {
7179 @@ -999,16 +878,16 @@
7180                         connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7181                 }
7182                 break;
7183 -       case CON_STATE_READ_POST: 
7184 +       case CON_STATE_READ_POST:
7185                 for (c = cq->first; c && (dst_cq->bytes_in != (off_t)con->request.content_length); c = c->next) {
7186                         off_t weWant, weHave, toRead;
7187 -                       
7188 +
7189                         weWant = con->request.content_length - dst_cq->bytes_in;
7190 -                       
7191 +
7192                         assert(c->mem->used);
7193 -                       
7194 +
7195                         weHave = c->mem->used - c->offset - 1;
7196 -                               
7197 +
7198                         toRead = weHave > weWant ? weWant : weHave;
7199  
7200                         /* the new way, copy everything into a chunkqueue whcih might use tempfiles */
7201 @@ -1017,13 +896,13 @@
7202                                 /* copy everything to max 1Mb sized tempfiles */
7203  
7204                                 /*
7205 -                                * if the last chunk is 
7206 +                                * if the last chunk is
7207                                  * - smaller than 1Mb (size < 1Mb)
7208                                  * - not read yet (offset == 0)
7209                                  * -> append to it
7210                                  * otherwise
7211 -                                * -> create a new chunk 
7212 -                                * 
7213 +                                * -> create a new chunk
7214 +                                *
7215                                  * */
7216  
7217                                 if (dst_cq->last &&
7218 @@ -1056,14 +935,14 @@
7219                                 /* we have a chunk, let's write to it */
7220  
7221                                 if (dst_c->file.fd == -1) {
7222 -                                       /* we don't have file to write to, 
7223 +                                       /* we don't have file to write to,
7224                                          * EACCES might be one reason.
7225                                          *
7226                                          * Instead of sending 500 we send 413 and say the request is too large
7227                                          *  */
7228  
7229                                         log_error_write(srv, __FILE__, __LINE__, "sbs",
7230 -                                                       "denying upload as opening to temp-file for upload failed:", 
7231 +                                                       "denying upload as opening to temp-file for upload failed:",
7232                                                         dst_c->file.name, strerror(errno));
7233  
7234                                         con->http_status = 413; /* Request-Entity too large */
7235 @@ -1074,15 +953,15 @@
7236                                 }
7237  
7238                                 if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) {
7239 -                                       /* write failed for some reason ... disk full ? */ 
7240 +                                       /* write failed for some reason ... disk full ? */
7241                                         log_error_write(srv, __FILE__, __LINE__, "sbs",
7242 -                                                       "denying upload as writing to file failed:", 
7243 +                                                       "denying upload as writing to file failed:",
7244                                                         dst_c->file.name, strerror(errno));
7245 -                                       
7246 +
7247                                         con->http_status = 413; /* Request-Entity too large */
7248                                         con->keep_alive = 0;
7249                                         connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7250 -                               
7251 +
7252                                         close(dst_c->file.fd);
7253                                         dst_c->file.fd = -1;
7254  
7255 @@ -1090,7 +969,7 @@
7256                                 }
7257  
7258                                 dst_c->file.length += toRead;
7259 -                                       
7260 +
7261                                 if (dst_cq->bytes_in + toRead == (off_t)con->request.content_length) {
7262                                         /* we read everything, close the chunk */
7263                                         close(dst_c->file.fd);
7264 @@ -1102,7 +981,7 @@
7265                                 b = chunkqueue_get_append_buffer(dst_cq);
7266                                 buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead);
7267                         }
7268 -                       
7269 +
7270                         c->offset += toRead;
7271                         dst_cq->bytes_in += toRead;
7272                 }
7273 @@ -1111,7 +990,7 @@
7274                 if (dst_cq->bytes_in == (off_t)con->request.content_length) {
7275                         connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7276                 }
7277 -                       
7278 +
7279                 break;
7280         }
7281  
7282 @@ -1123,100 +1002,104 @@
7283  handler_t connection_handle_fdevent(void *s, void *context, int revents) {
7284         server     *srv = (server *)s;
7285         connection *con = context;
7286 -       
7287 +
7288         joblist_append(srv, con);
7289 -       
7290 +
7291         if (revents & FDEVENT_IN) {
7292                 con->is_readable = 1;
7293 -#if 0
7294 -               log_error_write(srv, __FILE__, __LINE__, "sd", "read-wait - done", con->fd);
7295 -#endif
7296         }
7297         if (revents & FDEVENT_OUT) {
7298                 con->is_writable = 1;
7299                 /* we don't need the event twice */
7300         }
7301 -       
7302 -       
7303 +
7304 +
7305         if (revents & ~(FDEVENT_IN | FDEVENT_OUT)) {
7306                 /* looks like an error */
7307 -                                               
7308 +
7309                 /* FIXME: revents = 0x19 still means that we should read from the queue */
7310                 if (revents & FDEVENT_HUP) {
7311                         if (con->state == CON_STATE_CLOSE) {
7312                                 con->close_timeout_ts = 0;
7313                         } else {
7314                                 /* sigio reports the wrong event here
7315 -                                * 
7316 -                                * there was no HUP at all 
7317 +                                *
7318 +                                * there was no HUP at all
7319                                  */
7320  #ifdef USE_LINUX_SIGIO
7321                                 if (srv->ev->in_sigio == 1) {
7322                                         log_error_write(srv, __FILE__, __LINE__, "sd",
7323 -                                               "connection closed: poll() -> HUP", con->fd);
7324 +                                               "connection closed: poll() -> HUP", con->sock->fd);
7325                                 } else {
7326                                         connection_set_state(srv, con, CON_STATE_ERROR);
7327                                 }
7328  #else
7329                                 connection_set_state(srv, con, CON_STATE_ERROR);
7330  #endif
7331 -                               
7332 +
7333                         }
7334                 } else if (revents & FDEVENT_ERR) {
7335  #ifndef USE_LINUX_SIGIO
7336                         log_error_write(srv, __FILE__, __LINE__, "sd",
7337 -                                       "connection closed: poll() -> ERR", con->fd);
7338 -#endif 
7339 +                                       "connection closed: poll() -> ERR", con->sock->fd);
7340 +#endif
7341                         connection_set_state(srv, con, CON_STATE_ERROR);
7342                 } else {
7343                         log_error_write(srv, __FILE__, __LINE__, "sd",
7344                                         "connection closed: poll() -> ???", revents);
7345 -               } 
7346 +               }
7347         }
7348 -       
7349 +
7350         if (con->state == CON_STATE_READ ||
7351             con->state == CON_STATE_READ_POST) {
7352                 connection_handle_read_state(srv, con);
7353 +               /**
7354 +                * if SSL_read() is not readin in the full packet we won't get
7355 +                * a fdevent as the low-level has already fetched everything.
7356 +                *
7357 +                * we have to call the state-engine to read the rest of the packet
7358 +                */
7359 +               if (con->is_readable) joblist_append(srv, con);
7360         }
7361 -       
7362 +
7363         if (con->state == CON_STATE_WRITE &&
7364             !chunkqueue_is_empty(con->write_queue) &&
7365             con->is_writable) {
7366 -               
7367 +
7368                 if (-1 == connection_handle_write(srv, con)) {
7369                         connection_set_state(srv, con, CON_STATE_ERROR);
7370 -                       
7371 +
7372                         log_error_write(srv, __FILE__, __LINE__, "ds",
7373 -                                       con->fd,
7374 +                                       con->sock->fd,
7375                                         "handle write failed.");
7376                 } else if (con->state == CON_STATE_WRITE) {
7377                         con->write_request_ts = srv->cur_ts;
7378                 }
7379         }
7380 -       
7381 +
7382         if (con->state == CON_STATE_CLOSE) {
7383                 /* flush the read buffers */
7384                 int b;
7385 -               
7386 -               if (ioctl(con->fd, FIONREAD, &b)) {
7387 +
7388 +               if (ioctl(con->sock->fd, FIONREAD, &b)) {
7389                         log_error_write(srv, __FILE__, __LINE__, "ss",
7390                                         "ioctl() failed", strerror(errno));
7391                 }
7392 -               
7393 +
7394                 if (b > 0) {
7395                         char buf[1024];
7396                         log_error_write(srv, __FILE__, __LINE__, "sdd",
7397 -                                       "CLOSE-read()", con->fd, b);
7398 -                       
7399 +                                       "CLOSE-read()", con->sock->fd, b);
7400 +
7401                         /* */
7402 -                       read(con->fd, buf, sizeof(buf));
7403 +                       read(con->sock->fd, buf, sizeof(buf));
7404                 } else {
7405                         /* nothing to read */
7406 -                       
7407 +
7408                         con->close_timeout_ts = 0;
7409                 }
7410         }
7411 -       
7412 +
7413         return HANDLER_FINISHED;
7414  }
7415  
7416 @@ -1229,63 +1112,68 @@
7417         sock_addr cnt_addr;
7418         socklen_t cnt_len;
7419         /* accept it and register the fd */
7420 -       
7421 +
7422         cnt_len = sizeof(cnt_addr);
7423  
7424 -       if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7425 +       if (-1 == (cnt = accept(srv_socket->sock->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7426 +#ifdef _WIN32
7427 +               errno = WSAGetLastError();
7428 +#endif
7429                 if ((errno != EAGAIN) &&
7430 +                   (errno != EWOULDBLOCK) &&
7431                     (errno != EINTR)) {
7432 -                       log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno);
7433 +                       log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), srv_socket->sock->fd);
7434                 }
7435                 return NULL;
7436         } else {
7437                 connection *con;
7438 -               
7439 +
7440                 srv->cur_fds++;
7441 -               
7442 +
7443                 /* ok, we have the connection, register it */
7444  #if 0
7445                 log_error_write(srv, __FILE__, __LINE__, "sd",
7446                                 "appected()", cnt);
7447  #endif
7448                 srv->con_opened++;
7449 -               
7450 +
7451                 con = connections_get_new_connection(srv);
7452 -               
7453 -               con->fd = cnt;
7454 -               con->fde_ndx = -1;
7455 -#if 0          
7456 +               con->sock->fd = cnt;
7457 +               con->sock->fde_ndx = -1;
7458 +#if 0
7459                 gettimeofday(&(con->start_tv), NULL);
7460 -#endif         
7461 -               fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con);
7462 -               
7463 +#endif
7464 +               fdevent_register(srv->ev, con->sock, connection_handle_fdevent, con);
7465 +
7466                 connection_set_state(srv, con, CON_STATE_REQUEST_START);
7467 -               
7468 +
7469                 con->connection_start = srv->cur_ts;
7470                 con->dst_addr = cnt_addr;
7471                 buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
7472                 con->srv_socket = srv_socket;
7473 -               
7474 -               if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) {
7475 +
7476 +               if (-1 == (fdevent_fcntl_set(srv->ev, con->sock))) {
7477                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
7478 +                       connection_close(srv, con);
7479                         return NULL;
7480                 }
7481  #ifdef USE_OPENSSL
7482                 /* connect FD to SSL */
7483                 if (srv_socket->is_ssl) {
7484 -                       if (NULL == (con->ssl = SSL_new(srv_socket->ssl_ctx))) {
7485 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
7486 +                       if (NULL == (con->sock->ssl = SSL_new(srv_socket->ssl_ctx))) {
7487 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7488                                                 ERR_error_string(ERR_get_error(), NULL));
7489 -                               
7490 +                               connection_close(srv, con);
7491                                 return NULL;
7492                         }
7493 -                       
7494 -                       SSL_set_accept_state(con->ssl);
7495 +
7496 +                       SSL_set_accept_state(con->sock->ssl);
7497                         con->conf.is_ssl=1;
7498 -                       
7499 -                       if (1 != (SSL_set_fd(con->ssl, cnt))) {
7500 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
7501 +
7502 +                       if (1 != (SSL_set_fd(con->sock->ssl, cnt))) {
7503 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7504                                                 ERR_error_string(ERR_get_error(), NULL));
7505 +                               connection_close(srv, con);
7506                                 return NULL;
7507                         }
7508                 }
7509 @@ -1300,102 +1188,102 @@
7510  #ifdef USE_OPENSSL
7511         server_socket *srv_sock = con->srv_socket;
7512  #endif
7513 -       
7514 +
7515         if (srv->srvconf.log_state_handling) {
7516 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
7517 -                               "state at start", 
7518 -                               con->fd,
7519 +               log_error_write(srv, __FILE__, __LINE__, "sds",
7520 +                               "state at start",
7521 +                               con->sock->fd,
7522                                 connection_get_state(con->state));
7523         }
7524  
7525         while (done == 0) {
7526                 size_t ostate = con->state;
7527                 int b;
7528 -               
7529 +
7530                 switch (con->state) {
7531                 case CON_STATE_REQUEST_START: /* transient */
7532                         if (srv->srvconf.log_state_handling) {
7533 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7534 -                                               "state for fd", con->fd, connection_get_state(con->state));
7535 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7536 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7537                         }
7538 -                       
7539 +
7540                         con->request_start = srv->cur_ts;
7541                         con->read_idle_ts = srv->cur_ts;
7542 -                       
7543 +
7544                         con->request_count++;
7545                         con->loops_per_request = 0;
7546 -                       
7547 +
7548                         connection_set_state(srv, con, CON_STATE_READ);
7549 -                       
7550 +
7551                         break;
7552                 case CON_STATE_REQUEST_END: /* transient */
7553                         if (srv->srvconf.log_state_handling) {
7554 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7555 -                                               "state for fd", con->fd, connection_get_state(con->state));
7556 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7557 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7558                         }
7559 -                       
7560 +
7561                         if (http_request_parse(srv, con)) {
7562                                 /* we have to read some data from the POST request */
7563 -                               
7564 +
7565                                 connection_set_state(srv, con, CON_STATE_READ_POST);
7566  
7567                                 break;
7568                         }
7569 -                       
7570 +
7571                         connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7572 -                       
7573 +
7574                         break;
7575                 case CON_STATE_HANDLE_REQUEST:
7576 -                       /* 
7577 +                       /*
7578                          * the request is parsed
7579 -                        * 
7580 +                        *
7581                          * decided what to do with the request
7582 -                        * - 
7583 -                        * 
7584 -                        * 
7585 +                        * -
7586 +                        *
7587 +                        *
7588                          */
7589 -                       
7590 +
7591                         if (srv->srvconf.log_state_handling) {
7592 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7593 -                                               "state for fd", con->fd, connection_get_state(con->state));
7594 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7595 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7596                         }
7597 -                       
7598 +
7599                         switch (r = http_response_prepare(srv, con)) {
7600                         case HANDLER_FINISHED:
7601                                 if (con->http_status == 404 ||
7602                                     con->http_status == 403) {
7603                                         /* 404 error-handler */
7604 -                                       
7605 -                                       if (con->in_error_handler == 0 && 
7606 +
7607 +                                       if (con->in_error_handler == 0 &&
7608                                             (!buffer_is_empty(con->conf.error_handler) ||
7609                                              !buffer_is_empty(con->error_handler))) {
7610                                                 /* call error-handler */
7611 -                                               
7612 +
7613                                                 con->error_handler_saved_status = con->http_status;
7614                                                 con->http_status = 0;
7615 -                                               
7616 +
7617                                                 if (buffer_is_empty(con->error_handler)) {
7618                                                         buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
7619                                                 } else {
7620                                                         buffer_copy_string_buffer(con->request.uri, con->error_handler);
7621                                                 }
7622                                                 buffer_reset(con->physical.path);
7623 -                                               
7624 +
7625                                                 con->in_error_handler = 1;
7626 -                                               
7627 +
7628                                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7629 -                                               
7630 +
7631                                                 done = -1;
7632                                                 break;
7633                                         } else if (con->in_error_handler) {
7634                                                 /* error-handler is a 404 */
7635 -                                               
7636 +
7637                                                 /* continue as normal, status is the same */
7638 -                                               log_error_write(srv, __FILE__, __LINE__, "sb", 
7639 +                                               log_error_write(srv, __FILE__, __LINE__, "sb",
7640                                                                 "Warning: Either the error-handler returned status 404 or the error-handler itself was not found:", con->request.uri);
7641 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
7642 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
7643                                                                 "returning the original status", con->error_handler_saved_status);
7644 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
7645 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
7646                                                                 "If this is a rails app: check your production.log");
7647                                                 con->http_status = con->error_handler_saved_status;
7648                                         }
7649 @@ -1403,73 +1291,73 @@
7650                                         /* error-handler is back and has generated content */
7651                                         /* if Status: was set, take it otherwise use 200 */
7652                                 }
7653 -                               
7654 +
7655                                 if (con->http_status == 0) con->http_status = 200;
7656 -                               
7657 +
7658                                 /* we have something to send, go on */
7659                                 connection_set_state(srv, con, CON_STATE_RESPONSE_START);
7660                                 break;
7661                         case HANDLER_WAIT_FOR_FD:
7662                                 srv->want_fds++;
7663 -                               
7664 +
7665                                 fdwaitqueue_append(srv, con);
7666 -                               
7667 +
7668                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7669 -                               
7670 +
7671                                 break;
7672                         case HANDLER_COMEBACK:
7673                                 done = -1;
7674                         case HANDLER_WAIT_FOR_EVENT:
7675                                 /* come back here */
7676                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7677 -                               
7678 +
7679                                 break;
7680                         case HANDLER_ERROR:
7681                                 /* something went wrong */
7682                                 connection_set_state(srv, con, CON_STATE_ERROR);
7683                                 break;
7684                         default:
7685 -                               log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r);
7686 +                               log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->sock->fd, r);
7687                                 break;
7688                         }
7689 -                       
7690 +
7691                         break;
7692                 case CON_STATE_RESPONSE_START:
7693 -                       /* 
7694 +                       /*
7695                          * the decision is done
7696                          * - create the HTTP-Response-Header
7697 -                        * 
7698 +                        *
7699                          */
7700 -                       
7701 +
7702                         if (srv->srvconf.log_state_handling) {
7703 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7704 -                                               "state for fd", con->fd, connection_get_state(con->state));
7705 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7706 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7707                         }
7708 -                       
7709 +
7710                         if (-1 == connection_handle_write_prepare(srv, con)) {
7711                                 connection_set_state(srv, con, CON_STATE_ERROR);
7712 -                               
7713 +
7714                                 break;
7715                         }
7716 -                       
7717 +
7718                         connection_set_state(srv, con, CON_STATE_WRITE);
7719                         break;
7720                 case CON_STATE_RESPONSE_END: /* transient */
7721                         /* log the request */
7722 -                       
7723 +
7724                         if (srv->srvconf.log_state_handling) {
7725 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7726 -                                               "state for fd", con->fd, connection_get_state(con->state));
7727 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7728 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7729                         }
7730 -                       
7731 +
7732                         plugins_call_handle_request_done(srv, con);
7733 -                       
7734 +
7735                         srv->con_written++;
7736 -                       
7737 +
7738                         if (con->keep_alive) {
7739                                 connection_set_state(srv, con, CON_STATE_REQUEST_START);
7740 -                               
7741 -#if 0                                  
7742 +
7743 +#if 0
7744                                 con->request_start = srv->cur_ts;
7745                                 con->read_idle_ts = srv->cur_ts;
7746  #endif
7747 @@ -1482,103 +1370,103 @@
7748                                         log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r);
7749                                         break;
7750                                 }
7751 -                               
7752 +
7753  #ifdef USE_OPENSSL
7754                                 if (srv_sock->is_ssl) {
7755 -                                       switch (SSL_shutdown(con->ssl)) {
7756 +                                       switch (SSL_shutdown(con->sock->ssl)) {
7757                                         case 1:
7758                                                 /* done */
7759                                                 break;
7760                                         case 0:
7761 -                                               /* wait for fd-event 
7762 -                                                * 
7763 +                                               /* wait for fd-event
7764 +                                                *
7765                                                  * FIXME: wait for fdevent and call SSL_shutdown again
7766 -                                                * 
7767 +                                                *
7768                                                  */
7769 -                                               
7770 +
7771                                                 break;
7772                                         default:
7773 -                                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
7774 +                                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7775                                                                 ERR_error_string(ERR_get_error(), NULL));
7776                                         }
7777                                 }
7778  #endif
7779                                 connection_close(srv, con);
7780 -                               
7781 +
7782                                 srv->con_closed++;
7783                         }
7784 -                       
7785 +
7786                         connection_reset(srv, con);
7787 -                       
7788 +
7789                         break;
7790                 case CON_STATE_CONNECT:
7791                         if (srv->srvconf.log_state_handling) {
7792 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7793 -                                               "state for fd", con->fd, connection_get_state(con->state));
7794 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7795 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7796                         }
7797 -                       
7798 +
7799                         chunkqueue_reset(con->read_queue);
7800 -                       
7801 +
7802                         con->request_count = 0;
7803 -                       
7804 +
7805                         break;
7806                 case CON_STATE_CLOSE:
7807                         if (srv->srvconf.log_state_handling) {
7808 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7809 -                                               "state for fd", con->fd, connection_get_state(con->state));
7810 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7811 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7812                         }
7813 -                       
7814 +
7815                         if (con->keep_alive) {
7816 -                               if (ioctl(con->fd, FIONREAD, &b)) {
7817 +                               if (ioctl(con->sock->fd, FIONREAD, &b)) {
7818                                         log_error_write(srv, __FILE__, __LINE__, "ss",
7819                                                         "ioctl() failed", strerror(errno));
7820                                 }
7821                                 if (b > 0) {
7822                                         char buf[1024];
7823                                         log_error_write(srv, __FILE__, __LINE__, "sdd",
7824 -                                                       "CLOSE-read()", con->fd, b);
7825 -                                       
7826 +                                                       "CLOSE-read()", con->sock->fd, b);
7827 +
7828                                         /* */
7829 -                                       read(con->fd, buf, sizeof(buf));
7830 +                                       read(con->sock->fd, buf, sizeof(buf));
7831                                 } else {
7832                                         /* nothing to read */
7833 -                                       
7834 +
7835                                         con->close_timeout_ts = 0;
7836                                 }
7837                         } else {
7838                                 con->close_timeout_ts = 0;
7839                         }
7840 -                       
7841 +
7842                         if (srv->cur_ts - con->close_timeout_ts > 1) {
7843                                 connection_close(srv, con);
7844 -                               
7845 +
7846                                 if (srv->srvconf.log_state_handling) {
7847 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
7848 -                                                       "connection closed for fd", con->fd);
7849 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
7850 +                                                       "connection closed for fd", con->sock->fd);
7851                                 }
7852                         }
7853 -                       
7854 +
7855                         break;
7856                 case CON_STATE_READ_POST:
7857                 case CON_STATE_READ:
7858                         if (srv->srvconf.log_state_handling) {
7859 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7860 -                                               "state for fd", con->fd, connection_get_state(con->state));
7861 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7862 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7863                         }
7864 -                       
7865 +
7866                         connection_handle_read_state(srv, con);
7867                         break;
7868                 case CON_STATE_WRITE:
7869                         if (srv->srvconf.log_state_handling) {
7870 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7871 -                                               "state for fd", con->fd, connection_get_state(con->state));
7872 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7873 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7874                         }
7875 -                       
7876 +
7877                         /* only try to write if we have something in the queue */
7878                         if (!chunkqueue_is_empty(con->write_queue)) {
7879  #if 0
7880                                 log_error_write(srv, __FILE__, __LINE__, "dsd",
7881 -                                               con->fd,
7882 +                                               con->sock->fd,
7883                                                 "packets to write:",
7884                                                 con->write_queue->used);
7885  #endif
7886 @@ -1586,17 +1474,17 @@
7887                         if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) {
7888                                 if (-1 == connection_handle_write(srv, con)) {
7889                                         log_error_write(srv, __FILE__, __LINE__, "ds",
7890 -                                                       con->fd,
7891 +                                                       con->sock->fd,
7892                                                         "handle write failed.");
7893                                         connection_set_state(srv, con, CON_STATE_ERROR);
7894                                 } else if (con->state == CON_STATE_WRITE) {
7895                                         con->write_request_ts = srv->cur_ts;
7896                                 }
7897                         }
7898 -                       
7899 +
7900                         break;
7901                 case CON_STATE_ERROR: /* transient */
7902 -                       
7903 +
7904                         /* even if the connection was drop we still have to write it to the access log */
7905                         if (con->http_status) {
7906                                 plugins_call_handle_request_done(srv, con);
7907 @@ -1604,28 +1492,28 @@
7908  #ifdef USE_OPENSSL
7909                         if (srv_sock->is_ssl) {
7910                                 int ret;
7911 -                               switch ((ret = SSL_shutdown(con->ssl))) {
7912 +                               switch ((ret = SSL_shutdown(con->sock->ssl))) {
7913                                 case 1:
7914                                         /* ok */
7915                                         break;
7916                                 case 0:
7917 -                                       SSL_shutdown(con->ssl);
7918 +                                       SSL_shutdown(con->sock->ssl);
7919                                         break;
7920                                 default:
7921 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", 
7922 -                                                       SSL_get_error(con->ssl, ret), 
7923 +                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
7924 +                                                       SSL_get_error(con->sock->ssl, ret),
7925                                                         ERR_error_string(ERR_get_error(), NULL));
7926                                         return -1;
7927                                 }
7928                         }
7929  #endif
7930 -                       
7931 +
7932                         switch(con->mode) {
7933                         case DIRECT:
7934  #if 0
7935 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
7936 -                                               "emergency exit: direct", 
7937 -                                               con->fd);
7938 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
7939 +                                               "emergency exit: direct",
7940 +                                               con->sock->fd);
7941  #endif
7942                                 break;
7943                         default:
7944 @@ -1639,35 +1527,35 @@
7945                                 }
7946                                 break;
7947                         }
7948 -                       
7949 +
7950                         connection_reset(srv, con);
7951 -                       
7952 +
7953                         /* close the connection */
7954                         if ((con->keep_alive == 1) &&
7955 -                           (0 == shutdown(con->fd, SHUT_WR))) {
7956 +                           (0 == shutdown(con->sock->fd, SHUT_WR))) {
7957                                 con->close_timeout_ts = srv->cur_ts;
7958                                 connection_set_state(srv, con, CON_STATE_CLOSE);
7959 -                               
7960 +
7961                                 if (srv->srvconf.log_state_handling) {
7962 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
7963 -                                                       "shutdown for fd", con->fd);
7964 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
7965 +                                                       "shutdown for fd", con->sock->fd);
7966                                 }
7967                         } else {
7968                                 connection_close(srv, con);
7969                         }
7970 -                       
7971 +
7972                         con->keep_alive = 0;
7973 -                       
7974 +
7975                         srv->con_closed++;
7976 -                       
7977 +
7978                         break;
7979                 default:
7980 -                       log_error_write(srv, __FILE__, __LINE__, "sdd", 
7981 -                                       "unknown state:", con->fd, con->state);
7982 -                       
7983 +                       log_error_write(srv, __FILE__, __LINE__, "sdd",
7984 +                                       "unknown state:", con->sock->fd, con->state);
7985 +
7986                         break;
7987                 }
7988 -               
7989 +
7990                 if (done == -1) {
7991                         done = 0;
7992                 } else if (ostate == con->state) {
7993 @@ -1676,33 +1564,33 @@
7994         }
7995  
7996         if (srv->srvconf.log_state_handling) {
7997 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
7998 -                               "state at exit:", 
7999 -                               con->fd,
8000 +               log_error_write(srv, __FILE__, __LINE__, "sds",
8001 +                               "state at exit:",
8002 +                               con->sock->fd,
8003                                 connection_get_state(con->state));
8004         }
8005 -       
8006 +
8007         switch(con->state) {
8008         case CON_STATE_READ_POST:
8009         case CON_STATE_READ:
8010         case CON_STATE_CLOSE:
8011 -               fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN);
8012 +               fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
8013                 break;
8014         case CON_STATE_WRITE:
8015 -               /* request write-fdevent only if we really need it 
8016 +               /* request write-fdevent only if we really need it
8017                  * - if we have data to write
8018 -                * - if the socket is not writable yet 
8019 +                * - if the socket is not writable yet
8020                  */
8021 -               if (!chunkqueue_is_empty(con->write_queue) && 
8022 +               if (!chunkqueue_is_empty(con->write_queue) &&
8023                     (con->is_writable == 0) &&
8024                     (con->traffic_limit_reached == 0)) {
8025 -                       fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT);
8026 +                       fdevent_event_add(srv->ev, con->sock, FDEVENT_OUT);
8027                 } else {
8028 -                       fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8029 +                       fdevent_event_del(srv->ev, con->sock);
8030                 }
8031                 break;
8032         default:
8033 -               fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8034 +               fdevent_event_del(srv->ev, con->sock);
8035                 break;
8036         }
8037  
8038 --- ../lighttpd-1.4.11/src/crc32.h      2005-09-30 20:18:59.000000000 +0300
8039 +++ lighttpd-1.4.12/src/crc32.h 2006-07-16 00:26:04.000000000 +0300
8040 @@ -6,6 +6,7 @@
8041  #endif
8042  
8043  #include <sys/types.h>
8044 +#include <stdlib.h>
8045  
8046  #if defined HAVE_STDINT_H
8047  #include <stdint.h>
8048 @@ -13,6 +14,10 @@
8049  #include <inttypes.h>
8050  #endif
8051  
8052 +#ifdef _WIN32
8053 +#define uint32_t unsigned __int32
8054 +#endif
8055 +
8056  uint32_t generate_crc32c(char *string, size_t length);
8057  
8058  #endif
8059 --- ../lighttpd-1.4.11/src/data_array.c 2005-08-23 17:36:12.000000000 +0300
8060 +++ lighttpd-1.4.12/src/data_array.c    2006-07-16 00:26:04.000000000 +0300
8061 @@ -17,16 +17,16 @@
8062  
8063  static void data_array_free(data_unset *d) {
8064         data_array *ds = (data_array *)d;
8065 -       
8066 +
8067         buffer_free(ds->key);
8068         array_free(ds->value);
8069 -       
8070 +
8071         free(d);
8072  }
8073  
8074  static void data_array_reset(data_unset *d) {
8075         data_array *ds = (data_array *)d;
8076 -       
8077 +
8078         /* reused array elements */
8079         buffer_reset(ds->key);
8080         array_reset(ds->value);
8081 @@ -36,7 +36,7 @@
8082         UNUSED(dst);
8083  
8084         src->free(src);
8085 -       
8086 +
8087         return 0;
8088  }
8089  
8090 @@ -48,18 +48,18 @@
8091  
8092  data_array *data_array_init(void) {
8093         data_array *ds;
8094 -       
8095 +
8096         ds = calloc(1, sizeof(*ds));
8097 -       
8098 +
8099         ds->key = buffer_init();
8100         ds->value = array_init();
8101 -       
8102 +
8103         ds->copy = data_array_copy;
8104         ds->free = data_array_free;
8105         ds->reset = data_array_reset;
8106         ds->insert_dup = data_array_insert_dup;
8107         ds->print = data_array_print;
8108         ds->type = TYPE_ARRAY;
8109 -       
8110 +
8111         return ds;
8112  }
8113 --- ../lighttpd-1.4.11/src/data_config.c        2005-08-17 12:53:19.000000000 +0300
8114 +++ lighttpd-1.4.12/src/data_config.c   2006-07-16 00:26:03.000000000 +0300
8115 @@ -17,26 +17,26 @@
8116  
8117  static void data_config_free(data_unset *d) {
8118         data_config *ds = (data_config *)d;
8119 -       
8120 +
8121         buffer_free(ds->key);
8122         buffer_free(ds->op);
8123         buffer_free(ds->comp_key);
8124 -       
8125 +
8126         array_free(ds->value);
8127         array_free(ds->childs);
8128 -       
8129 +
8130         if (ds->string) buffer_free(ds->string);
8131  #ifdef HAVE_PCRE_H
8132         if (ds->regex) pcre_free(ds->regex);
8133         if (ds->regex_study) pcre_free(ds->regex_study);
8134  #endif
8135 -       
8136 +
8137         free(d);
8138  }
8139  
8140  static void data_config_reset(data_unset *d) {
8141         data_config *ds = (data_config *)d;
8142 -       
8143 +
8144         /* reused array elements */
8145         buffer_reset(ds->key);
8146         buffer_reset(ds->comp_key);
8147 @@ -45,9 +45,9 @@
8148  
8149  static int data_config_insert_dup(data_unset *dst, data_unset *src) {
8150         UNUSED(dst);
8151 -       
8152 +
8153         src->free(src);
8154 -       
8155 +
8156         return 0;
8157  }
8158  
8159 @@ -56,7 +56,7 @@
8160         array *a = (array *)ds->value;
8161         size_t i;
8162         size_t maxlen;
8163 -       
8164 +
8165         if (0 == ds->context_ndx) {
8166                 fprintf(stderr, "config {\n");
8167         }
8168 @@ -117,22 +117,22 @@
8169  
8170  data_config *data_config_init(void) {
8171         data_config *ds;
8172 -       
8173 +
8174         ds = calloc(1, sizeof(*ds));
8175 -       
8176 +
8177         ds->key = buffer_init();
8178         ds->op = buffer_init();
8179         ds->comp_key = buffer_init();
8180         ds->value = array_init();
8181         ds->childs = array_init();
8182         ds->childs->is_weakref = 1;
8183 -       
8184 +
8185         ds->copy = data_config_copy;
8186         ds->free = data_config_free;
8187         ds->reset = data_config_reset;
8188         ds->insert_dup = data_config_insert_dup;
8189         ds->print = data_config_print;
8190         ds->type = TYPE_CONFIG;
8191 -       
8192 +
8193         return ds;
8194  }
8195 --- ../lighttpd-1.4.11/src/data_count.c 2005-08-23 17:36:12.000000000 +0300
8196 +++ lighttpd-1.4.12/src/data_count.c    2006-07-16 00:26:03.000000000 +0300
8197 @@ -16,53 +16,53 @@
8198  
8199  static void data_count_free(data_unset *d) {
8200         data_count *ds = (data_count *)d;
8201 -       
8202 +
8203         buffer_free(ds->key);
8204 -       
8205 +
8206         free(d);
8207  }
8208  
8209  static void data_count_reset(data_unset *d) {
8210         data_count *ds = (data_count *)d;
8211 -       
8212 +
8213         buffer_reset(ds->key);
8214 -       
8215 +
8216         ds->count = 0;
8217  }
8218  
8219  static int data_count_insert_dup(data_unset *dst, data_unset *src) {
8220         data_count *ds_dst = (data_count *)dst;
8221         data_count *ds_src = (data_count *)src;
8222 -       
8223 +
8224         ds_dst->count += ds_src->count;
8225 -       
8226 +
8227         src->free(src);
8228 -       
8229 +
8230         return 0;
8231  }
8232  
8233  static void data_count_print(const data_unset *d, int depth) {
8234         data_count *ds = (data_count *)d;
8235         UNUSED(depth);
8236 -       
8237 +
8238         fprintf(stderr, "count(%d)", ds->count);
8239  }
8240  
8241  
8242  data_count *data_count_init(void) {
8243         data_count *ds;
8244 -       
8245 +
8246         ds = calloc(1, sizeof(*ds));
8247 -       
8248 +
8249         ds->key = buffer_init();
8250         ds->count = 1;
8251 -       
8252 +
8253         ds->copy = data_count_copy;
8254         ds->free = data_count_free;
8255         ds->reset = data_count_reset;
8256         ds->insert_dup = data_count_insert_dup;
8257         ds->print = data_count_print;
8258         ds->type = TYPE_COUNT;
8259 -       
8260 +
8261         return ds;
8262  }
8263 --- ../lighttpd-1.4.11/src/data_fastcgi.c       2005-08-23 17:36:12.000000000 +0300
8264 +++ lighttpd-1.4.12/src/data_fastcgi.c  2006-07-16 00:26:04.000000000 +0300
8265 @@ -17,53 +17,53 @@
8266  
8267  static void data_fastcgi_free(data_unset *d) {
8268         data_fastcgi *ds = (data_fastcgi *)d;
8269 -       
8270 +
8271         buffer_free(ds->key);
8272         buffer_free(ds->host);
8273 -       
8274 +
8275         free(d);
8276  }
8277  
8278  static void data_fastcgi_reset(data_unset *d) {
8279         data_fastcgi *ds = (data_fastcgi *)d;
8280 -       
8281 +
8282         buffer_reset(ds->key);
8283         buffer_reset(ds->host);
8284 -       
8285 +
8286  }
8287  
8288  static int data_fastcgi_insert_dup(data_unset *dst, data_unset *src) {
8289         UNUSED(dst);
8290  
8291         src->free(src);
8292 -       
8293 +
8294         return 0;
8295  }
8296  
8297  static void data_fastcgi_print(const data_unset *d, int depth) {
8298         data_fastcgi *ds = (data_fastcgi *)d;
8299         UNUSED(depth);
8300 -       
8301 +
8302         fprintf(stderr, "fastcgi(%s)", ds->host->ptr);
8303  }
8304  
8305  
8306  data_fastcgi *data_fastcgi_init(void) {
8307         data_fastcgi *ds;
8308 -       
8309 +
8310         ds = calloc(1, sizeof(*ds));
8311 -       
8312 +
8313         ds->key = buffer_init();
8314         ds->host = buffer_init();
8315         ds->port = 0;
8316         ds->is_disabled = 0;
8317 -       
8318 +
8319         ds->copy = data_fastcgi_copy;
8320         ds->free = data_fastcgi_free;
8321         ds->reset = data_fastcgi_reset;
8322         ds->insert_dup = data_fastcgi_insert_dup;
8323         ds->print = data_fastcgi_print;
8324         ds->type = TYPE_FASTCGI;
8325 -       
8326 +
8327         return ds;
8328  }
8329 --- ../lighttpd-1.4.11/src/data_integer.c       2005-08-23 17:36:12.000000000 +0300
8330 +++ lighttpd-1.4.12/src/data_integer.c  2006-07-16 00:26:03.000000000 +0300
8331 @@ -16,15 +16,15 @@
8332  
8333  static void data_integer_free(data_unset *d) {
8334         data_integer *ds = (data_integer *)d;
8335 -       
8336 +
8337         buffer_free(ds->key);
8338 -       
8339 +
8340         free(d);
8341  }
8342  
8343  static void data_integer_reset(data_unset *d) {
8344         data_integer *ds = (data_integer *)d;
8345 -       
8346 +
8347         /* reused integer elements */
8348         buffer_reset(ds->key);
8349         ds->value = 0;
8350 @@ -32,9 +32,9 @@
8351  
8352  static int data_integer_insert_dup(data_unset *dst, data_unset *src) {
8353         UNUSED(dst);
8354 -       
8355 +
8356         src->free(src);
8357 -       
8358 +
8359         return 0;
8360  }
8361  
8362 @@ -48,18 +48,18 @@
8363  
8364  data_integer *data_integer_init(void) {
8365         data_integer *ds;
8366 -       
8367 +
8368         ds = calloc(1, sizeof(*ds));
8369 -       
8370 +
8371         ds->key = buffer_init();
8372         ds->value = 0;
8373 -       
8374 +
8375         ds->copy = data_integer_copy;
8376         ds->free = data_integer_free;
8377         ds->reset = data_integer_reset;
8378         ds->insert_dup = data_integer_insert_dup;
8379         ds->print = data_integer_print;
8380         ds->type = TYPE_INTEGER;
8381 -       
8382 +
8383         return ds;
8384  }
8385 --- ../lighttpd-1.4.11/src/data_string.c        2005-08-23 17:36:12.000000000 +0300
8386 +++ lighttpd-1.4.12/src/data_string.c   2006-07-16 00:26:04.000000000 +0300
8387 @@ -17,16 +17,16 @@
8388  
8389  static void data_string_free(data_unset *d) {
8390         data_string *ds = (data_string *)d;
8391 -       
8392 +
8393         buffer_free(ds->key);
8394         buffer_free(ds->value);
8395 -       
8396 +
8397         free(d);
8398  }
8399  
8400  static void data_string_reset(data_unset *d) {
8401         data_string *ds = (data_string *)d;
8402 -       
8403 +
8404         /* reused array elements */
8405         buffer_reset(ds->key);
8406         buffer_reset(ds->value);
8407 @@ -35,23 +35,23 @@
8408  static int data_string_insert_dup(data_unset *dst, data_unset *src) {
8409         data_string *ds_dst = (data_string *)dst;
8410         data_string *ds_src = (data_string *)src;
8411 -       
8412 +
8413         if (ds_dst->value->used) {
8414                 buffer_append_string(ds_dst->value, ", ");
8415                 buffer_append_string_buffer(ds_dst->value, ds_src->value);
8416         } else {
8417                 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
8418         }
8419 -       
8420 +
8421         src->free(src);
8422 -       
8423 +
8424         return 0;
8425  }
8426  
8427  static int data_response_insert_dup(data_unset *dst, data_unset *src) {
8428         data_string *ds_dst = (data_string *)dst;
8429         data_string *ds_src = (data_string *)src;
8430 -       
8431 +
8432         if (ds_dst->value->used) {
8433                 buffer_append_string(ds_dst->value, "\r\n");
8434                 buffer_append_string_buffer(ds_dst->value, ds_dst->key);
8435 @@ -60,9 +60,9 @@
8436         } else {
8437                 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
8438         }
8439 -       
8440 +
8441         src->free(src);
8442 -       
8443 +
8444         return 0;
8445  }
8446  
8447 @@ -77,28 +77,28 @@
8448  
8449  data_string *data_string_init(void) {
8450         data_string *ds;
8451 -       
8452 +
8453         ds = calloc(1, sizeof(*ds));
8454         assert(ds);
8455 -       
8456 +
8457         ds->key = buffer_init();
8458         ds->value = buffer_init();
8459 -       
8460 +
8461         ds->copy = data_string_copy;
8462         ds->free = data_string_free;
8463         ds->reset = data_string_reset;
8464         ds->insert_dup = data_string_insert_dup;
8465         ds->print = data_string_print;
8466         ds->type = TYPE_STRING;
8467 -       
8468 +
8469         return ds;
8470  }
8471  
8472  data_string *data_response_init(void) {
8473         data_string *ds;
8474 -       
8475 +
8476         ds = data_string_init();
8477         ds->insert_dup = data_response_insert_dup;
8478 -       
8479 +
8480         return ds;
8481  }
8482 --- ../lighttpd-1.4.11/src/etag.c       2005-08-11 01:26:40.000000000 +0300
8483 +++ lighttpd-1.4.12/src/etag.c  2006-07-18 13:03:40.000000000 +0300
8484 @@ -4,7 +4,7 @@
8485  #include "etag.h"
8486  
8487  int etag_is_equal(buffer *etag, const char *matches) {
8488 -       if (0 == strcmp(etag->ptr, matches)) return 1;
8489 +       if (buffer_is_equal_string(etag, matches, strlen(matches))) return 1;
8490         return 0;
8491  }
8492  
8493 @@ -14,19 +14,19 @@
8494         buffer_append_off_t(etag, st->st_size);
8495         buffer_append_string_len(etag, CONST_STR_LEN("-"));
8496         buffer_append_long(etag, st->st_mtime);
8497 -       
8498 +
8499         return 0;
8500  }
8501  
8502  int etag_mutate(buffer *mut, buffer *etag) {
8503         size_t h, i;
8504 -       
8505 +
8506         for (h=0, i=0; i < etag->used; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
8507 -       
8508 +
8509         buffer_reset(mut);
8510         buffer_copy_string_len(mut, CONST_STR_LEN("\""));
8511         buffer_append_long(mut, h);
8512         buffer_append_string_len(mut, CONST_STR_LEN("\""));
8513 -       
8514 +
8515         return 0;
8516  }
8517 --- ../lighttpd-1.4.11/src/etag.h       2005-08-11 01:26:40.000000000 +0300
8518 +++ lighttpd-1.4.12/src/etag.h  2006-07-16 00:26:03.000000000 +0300
8519 @@ -3,13 +3,12 @@
8520  
8521  #include <sys/types.h>
8522  #include <sys/stat.h>
8523 -#include <unistd.h>
8524  
8525  #include "buffer.h"
8526  
8527  int etag_is_equal(buffer *etag, const char *matches);
8528  int etag_create(buffer *etag, struct stat *st);
8529  int etag_mutate(buffer *mut, buffer *etag);
8530 -       
8531 +
8532  
8533  #endif
8534 --- ../lighttpd-1.4.11/src/fastcgi.h    2005-08-11 01:26:40.000000000 +0300
8535 +++ lighttpd-1.4.12/src/fastcgi.h       2006-07-16 00:26:03.000000000 +0300
8536 @@ -1,4 +1,4 @@
8537 -/* 
8538 +/*
8539   * fastcgi.h --
8540   *
8541   *     Defines for the FastCGI protocol.
8542 @@ -123,7 +123,7 @@
8543  
8544  
8545  typedef struct {
8546 -    unsigned char type;    
8547 +    unsigned char type;
8548      unsigned char reserved[7];
8549  } FCGI_UnknownTypeBody;
8550  
8551 --- ../lighttpd-1.4.11/src/fdevent.c    2005-11-15 10:51:05.000000000 +0200
8552 +++ lighttpd-1.4.12/src/fdevent.c       2006-07-18 13:03:40.000000000 +0300
8553 @@ -2,7 +2,6 @@
8554  
8555  #include "settings.h"
8556  
8557 -#include <unistd.h>
8558  #include <stdlib.h>
8559  #include <string.h>
8560  #include <errno.h>
8561 @@ -11,60 +10,116 @@
8562  
8563  #include "fdevent.h"
8564  #include "buffer.h"
8565 +#include "log.h"
8566 +
8567 +#include "sys-socket.h"
8568 +
8569 +fdevent_revent *fdevent_revent_init(void) {
8570 +       STRUCT_INIT(fdevent_revent, revent);
8571 +
8572 +       return revent;
8573 +}
8574 +
8575 +void fdevent_revent_free(fdevent_revent *revent) {
8576 +       if (!revent) return;
8577 +
8578 +       free(revent);
8579 +}
8580 +
8581 +fdevent_revents *fdevent_revents_init(void) {
8582 +       STRUCT_INIT(fdevent_revents, revents);
8583 +
8584 +       return revents;
8585 +}
8586 +
8587 +void fdevent_revents_reset(fdevent_revents *revents) {
8588 +       if (!revents) return;
8589 +
8590 +       revents->used = 0;
8591 +}
8592 +
8593 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events) {
8594 +       fdevent_revent *revent;
8595 +
8596 +       if (revents->used == revents->size) {
8597 +               /* resize the events-array */
8598 +               revents->ptr = realloc(revents->ptr, (revents->size + 1) * sizeof(*(revents->ptr)));
8599 +               revents->ptr[revents->size++] = fdevent_revent_init();
8600 +       }
8601 +
8602 +       revent = revents->ptr[revents->used++];
8603 +       revent->fd = fd;
8604 +       revent->revents = events;
8605 +}
8606 +
8607 +void fdevent_revents_free(fdevent_revents *revents) {
8608 +       size_t i;
8609 +       
8610 +       if (!revents) return;
8611 +
8612 +       if (revents->size) {
8613 +               for (i = 0; i < revents->size; i++) {
8614 +                       fdevent_revent_free(revents->ptr[i]);
8615 +               }
8616 +
8617 +               free(revents->ptr);
8618 +       }
8619 +       free(revents);
8620 +}
8621  
8622  fdevents *fdevent_init(size_t maxfds, fdevent_handler_t type) {
8623         fdevents *ev;
8624 -       
8625 +
8626         ev = calloc(1, sizeof(*ev));
8627         ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray));
8628         ev->maxfds = maxfds;
8629 -       
8630 +
8631         switch(type) {
8632         case FDEVENT_HANDLER_POLL:
8633                 if (0 != fdevent_poll_init(ev)) {
8634 -                       fprintf(stderr, "%s.%d: event-handler poll failed\n", 
8635 +                       fprintf(stderr, "%s.%d: event-handler poll failed\n",
8636                                 __FILE__, __LINE__);
8637 -                       
8638 +
8639                         return NULL;
8640                 }
8641                 break;
8642         case FDEVENT_HANDLER_SELECT:
8643                 if (0 != fdevent_select_init(ev)) {
8644 -                       fprintf(stderr, "%s.%d: event-handler select failed\n", 
8645 +                       fprintf(stderr, "%s.%d: event-handler select failed\n",
8646                                 __FILE__, __LINE__);
8647                         return NULL;
8648                 }
8649                 break;
8650         case FDEVENT_HANDLER_LINUX_RTSIG:
8651                 if (0 != fdevent_linux_rtsig_init(ev)) {
8652 -                       fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
8653 +                       fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8654                                 __FILE__, __LINE__);
8655                         return NULL;
8656                 }
8657                 break;
8658         case FDEVENT_HANDLER_LINUX_SYSEPOLL:
8659                 if (0 != fdevent_linux_sysepoll_init(ev)) {
8660 -                       fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
8661 +                       fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8662                                 __FILE__, __LINE__);
8663                         return NULL;
8664                 }
8665                 break;
8666         case FDEVENT_HANDLER_SOLARIS_DEVPOLL:
8667                 if (0 != fdevent_solaris_devpoll_init(ev)) {
8668 -                       fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
8669 +                       fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8670                                 __FILE__, __LINE__);
8671                         return NULL;
8672                 }
8673                 break;
8674         case FDEVENT_HANDLER_FREEBSD_KQUEUE:
8675                 if (0 != fdevent_freebsd_kqueue_init(ev)) {
8676 -                       fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
8677 +                       fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8678                                 __FILE__, __LINE__);
8679                         return NULL;
8680                 }
8681                 break;
8682         default:
8683 -               fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n", 
8684 +               fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n",
8685                         __FILE__, __LINE__);
8686                 return NULL;
8687         }
8688 @@ -75,28 +130,29 @@
8689  void fdevent_free(fdevents *ev) {
8690         size_t i;
8691         if (!ev) return;
8692 -       
8693 +
8694         if (ev->free) ev->free(ev);
8695 -       
8696 +
8697         for (i = 0; i < ev->maxfds; i++) {
8698                 if (ev->fdarray[i]) free(ev->fdarray[i]);
8699         }
8700 -       
8701 +
8702         free(ev->fdarray);
8703         free(ev);
8704  }
8705  
8706  int fdevent_reset(fdevents *ev) {
8707         if (ev->reset) return ev->reset(ev);
8708 -       
8709 +
8710         return 0;
8711  }
8712  
8713  fdnode *fdnode_init() {
8714         fdnode *fdn;
8715 -       
8716 +
8717         fdn = calloc(1, sizeof(*fdn));
8718         fdn->fd = -1;
8719 +
8720         return fdn;
8721  }
8722  
8723 @@ -104,48 +160,40 @@
8724         free(fdn);
8725  }
8726  
8727 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) {
8728 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx) {
8729         fdnode *fdn;
8730 -       
8731 +
8732         fdn = fdnode_init();
8733         fdn->handler = handler;
8734 -       fdn->fd      = fd;
8735 +       fdn->fd      = sock->fd;
8736         fdn->ctx     = ctx;
8737 -       
8738 -       ev->fdarray[fd] = fdn;
8739 +
8740 +       ev->fdarray[sock->fd] = fdn;
8741  
8742         return 0;
8743  }
8744  
8745 -int fdevent_unregister(fdevents *ev, int fd) {
8746 +int fdevent_unregister(fdevents *ev, iosocket *sock) {
8747         fdnode *fdn;
8748          if (!ev) return 0;
8749 -       fdn = ev->fdarray[fd];
8750 -       
8751 +       fdn = ev->fdarray[sock->fd];
8752 +
8753         fdnode_free(fdn);
8754 -       
8755 -       ev->fdarray[fd] = NULL;
8756 -       
8757 +
8758 +       ev->fdarray[sock->fd] = NULL;
8759 +
8760         return 0;
8761  }
8762  
8763 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd) {
8764 -       int fde = fde_ndx ? *fde_ndx : -1;
8765 -       
8766 -       if (ev->event_del) fde = ev->event_del(ev, fde, fd);
8767 -       
8768 -       if (fde_ndx) *fde_ndx = fde;
8769 -       
8770 +int fdevent_event_del(fdevents *ev, iosocket *sock) {
8771 +       if (ev->event_del) ev->event_del(ev, sock);
8772 +
8773         return 0;
8774  }
8775  
8776 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events) {
8777 -       int fde = fde_ndx ? *fde_ndx : -1;
8778 -       
8779 -       if (ev->event_add) fde = ev->event_add(ev, fde, fd, events);
8780 -       
8781 -       if (fde_ndx) *fde_ndx = fde;
8782 -       
8783 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events) {
8784 +       if (ev->event_add) ev->event_add(ev, sock, events);
8785 +
8786         return 0;
8787  }
8788  
8789 @@ -154,49 +202,41 @@
8790         return ev->poll(ev, timeout_ms);
8791  }
8792  
8793 -int fdevent_event_get_revent(fdevents *ev, size_t ndx) {
8794 -       if (ev->event_get_revent == NULL) SEGFAULT();
8795 -       
8796 -       return ev->event_get_revent(ev, ndx);
8797 -}
8798 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
8799 +       size_t i;
8800  
8801 -int fdevent_event_get_fd(fdevents *ev, size_t ndx) {
8802 -       if (ev->event_get_fd == NULL) SEGFAULT();
8803 -       
8804 -       return ev->event_get_fd(ev, ndx);
8805 -}
8806 +       if (ev->get_revents == NULL) SEGFAULT();
8807  
8808 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd) {
8809 -       if (ev->fdarray[fd] == NULL) SEGFAULT();
8810 -       if (ev->fdarray[fd]->fd != fd) SEGFAULT();
8811 -       
8812 -       return ev->fdarray[fd]->handler;
8813 -}
8814 +       fdevent_revents_reset(revents);
8815  
8816 -void * fdevent_get_context(fdevents *ev, int fd) {
8817 -       if (ev->fdarray[fd] == NULL) SEGFAULT();
8818 -       if (ev->fdarray[fd]->fd != fd) SEGFAULT();
8819 -       
8820 -       return ev->fdarray[fd]->ctx;
8821 +       ev->get_revents(ev, event_count, revents);
8822 +
8823 +       /* patch the event handlers */
8824 +       for (i = 0; i < event_count; i++) {
8825 +               fdevent_revent *r = revents->ptr[i];
8826 +
8827 +               r->handler = ev->fdarray[r->fd]->handler;
8828 +               r->context = ev->fdarray[r->fd]->ctx;
8829 +       }
8830 +
8831 +       return 0;
8832  }
8833  
8834 -int fdevent_fcntl_set(fdevents *ev, int fd) {
8835 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock) {
8836 +#ifdef _WIN32
8837 +       int i = 1;
8838 +#endif
8839  #ifdef FD_CLOEXEC
8840         /* close fd on exec (cgi) */
8841 -       fcntl(fd, F_SETFD, FD_CLOEXEC);
8842 +       fcntl(sock->fd, F_SETFD, FD_CLOEXEC);
8843  #endif
8844 -       if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, fd);
8845 -#ifdef O_NONBLOCK      
8846 -       return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
8847 +       if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, sock->fd);
8848 +#ifdef O_NONBLOCK
8849 +       return fcntl(sock->fd, F_SETFL, O_NONBLOCK | O_RDWR);
8850 +#elif defined _WIN32
8851 +       return ioctlsocket(sock->fd, FIONBIO, &i);
8852  #else
8853         return 0;
8854  #endif
8855  }
8856  
8857 -
8858 -int fdevent_event_next_fdndx(fdevents *ev, int ndx) {
8859 -       if (ev->event_next_fdndx) return ev->event_next_fdndx(ev, ndx);
8860 -       
8861 -       return -1;
8862 -}
8863 -
8864 --- ../lighttpd-1.4.11/src/fdevent.h    2005-09-27 11:26:33.000000000 +0300
8865 +++ lighttpd-1.4.12/src/fdevent.h       2006-07-18 13:03:40.000000000 +0300
8866 @@ -7,6 +7,9 @@
8867  #include "settings.h"
8868  #include "bitset.h"
8869  
8870 +#include "iosocket.h"
8871 +#include "array-static.h"
8872 +
8873  /* select event-system */
8874  
8875  #if defined(HAVE_EPOLL_CTL) && defined(HAVE_SYS_EPOLL_H)
8876 @@ -17,13 +20,13 @@
8877  # include <sys/epoll.h>
8878  #endif
8879  
8880 -/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes 
8881 +/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes
8882   * under /usr/include/sys/ */
8883  #if defined HAVE_POLL && (defined(HAVE_SYS_POLL_H) || defined(HAVE_POLL_H))
8884  # define USE_POLL
8885  # ifdef HAVE_POLL_H
8886  #  include <poll.h>
8887 -# else 
8888 +# else
8889  #  include <sys/poll.h>
8890  # endif
8891  # if defined HAVE_SIGTIMEDWAIT && defined(__linux__)
8892 @@ -31,9 +34,11 @@
8893  #  include <signal.h>
8894  # endif
8895  #endif
8896 -
8897 +#ifdef _WIN32
8898 +# define HAVE_SELECT
8899 +#endif
8900  #if defined HAVE_SELECT
8901 -# ifdef __WIN32
8902 +# ifdef _WIN32
8903  #  include <winsock2.h>
8904  # endif
8905  # define USE_SELECT
8906 @@ -67,14 +72,14 @@
8907  #define FDEVENT_HUP    BV(4)
8908  #define FDEVENT_NVAL   BV(5)
8909  
8910 -typedef enum { FD_EVENT_TYPE_UNSET = -1, 
8911 -               FD_EVENT_TYPE_CONNECTION, 
8912 -               FD_EVENT_TYPE_FCGI_CONNECTION, 
8913 -               FD_EVENT_TYPE_DIRWATCH, 
8914 -               FD_EVENT_TYPE_CGI_CONNECTION 
8915 +typedef enum { FD_EVENT_TYPE_UNSET = -1,
8916 +               FD_EVENT_TYPE_CONNECTION,
8917 +               FD_EVENT_TYPE_FCGI_CONNECTION,
8918 +               FD_EVENT_TYPE_DIRWATCH,
8919 +               FD_EVENT_TYPE_CGI_CONNECTION
8920  } fd_event_t;
8921  
8922 -typedef enum { FDEVENT_HANDLER_UNSET, 
8923 +typedef enum { FDEVENT_HANDLER_UNSET,
8924                 FDEVENT_HANDLER_SELECT,
8925                 FDEVENT_HANDLER_POLL,
8926                 FDEVENT_HANDLER_LINUX_RTSIG,
8927 @@ -86,7 +91,7 @@
8928  
8929  /**
8930   * a mapping from fd to connection structure
8931 - * 
8932 + *
8933   */
8934  typedef struct {
8935         int fd;                  /**< the fd */
8936 @@ -96,43 +101,51 @@
8937         int revents;
8938  } fd_conn;
8939  
8940 +ARRAY_STATIC_DEF(fd_conn_buffer, fd_conn, );
8941 +
8942 +/**
8943 + * revents
8944 + */
8945  typedef struct {
8946 -       fd_conn *ptr;
8947 -       
8948 -       size_t size;
8949 -       size_t used;
8950 -} fd_conn_buffer;
8951 +       int fd;
8952 +       int revents;
8953 +
8954 +       fdevent_handler handler;
8955 +       void *context;
8956 +} fdevent_revent;
8957 +
8958 +ARRAY_STATIC_DEF(fdevent_revents, fdevent_revent, );
8959  
8960  /**
8961   * array of unused fd's
8962 - * 
8963 + *
8964   */
8965  
8966  typedef struct _fdnode {
8967 -       fdevent_handler handler;
8968 -       void *ctx;
8969 -       int fd;
8970 -       
8971 +       fdevent_handler handler; /* who handles the events for this fd */
8972 +       void *ctx;               /* opaque pointer which is passed as 3rd parameter to the handler */
8973 +       int fd;                  /* fd */
8974 +
8975         struct _fdnode *prev, *next;
8976  } fdnode;
8977  
8978  typedef struct {
8979         int *ptr;
8980 -       
8981 +
8982         size_t used;
8983         size_t size;
8984  } buffer_int;
8985  
8986  /**
8987   * fd-event handler for select(), poll() and rt-signals on Linux 2.4
8988 - * 
8989 + *
8990   */
8991  typedef struct fdevents {
8992         fdevent_handler_t type;
8993 -       
8994 -       fdnode **fdarray;
8995 +
8996 +       fdnode **fdarray; /* a list of fdnodes */
8997         size_t maxfds;
8998 -       
8999 +
9000  #ifdef USE_LINUX_SIGIO
9001         int in_sigio;
9002         int signum;
9003 @@ -146,21 +159,21 @@
9004  #endif
9005  #ifdef USE_POLL
9006         struct pollfd *pollfds;
9007 -       
9008 +
9009         size_t size;
9010         size_t used;
9011 -       
9012 +
9013         buffer_int unused;
9014  #endif
9015  #ifdef USE_SELECT
9016         fd_set select_read;
9017         fd_set select_write;
9018         fd_set select_error;
9019 -       
9020 +
9021         fd_set select_set_read;
9022         fd_set select_set_write;
9023         fd_set select_set_error;
9024 -       
9025 +
9026         int select_max_fd;
9027  #endif
9028  #ifdef USE_SOLARIS_DEVPOLL
9029 @@ -177,16 +190,13 @@
9030  #endif
9031         int (*reset)(struct fdevents *ev);
9032         void (*free)(struct fdevents *ev);
9033 -       
9034 -       int (*event_add)(struct fdevents *ev, int fde_ndx, int fd, int events);
9035 -       int (*event_del)(struct fdevents *ev, int fde_ndx, int fd);
9036 -       int (*event_get_revent)(struct fdevents *ev, size_t ndx);
9037 -       int (*event_get_fd)(struct fdevents *ev, size_t ndx);
9038 -       
9039 -       int (*event_next_fdndx)(struct fdevents *ev, int ndx);
9040 -       
9041 +
9042 +       int (*event_add)(struct fdevents *ev, iosocket *sock, int events);
9043 +       int (*event_del)(struct fdevents *ev, iosocket *sock);
9044 +       int (*get_revents)(struct fdevents *ev, size_t event_count, fdevent_revents *revents);
9045 +
9046         int (*poll)(struct fdevents *ev, int timeout_ms);
9047 -       
9048 +
9049         int (*fcntl_set)(struct fdevents *ev, int fd);
9050  } fdevents;
9051  
9052 @@ -194,22 +204,44 @@
9053  int fdevent_reset(fdevents *ev);
9054  void fdevent_free(fdevents *ev);
9055  
9056 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events);
9057 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd);
9058 -int fdevent_event_get_revent(fdevents *ev, size_t ndx);
9059 -int fdevent_event_get_fd(fdevents *ev, size_t ndx);
9060 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd);
9061 -void * fdevent_get_context(fdevents *ev, int fd);
9062 +/**
9063 + * call the plugin for the number of available events
9064 + */
9065 +int fdevent_poll(fdevents *ev, int timeout_ms);
9066 +/**
9067 + * get all available events
9068 + */
9069 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents);
9070  
9071 -int fdevent_event_next_fdndx(fdevents *ev, int ndx);
9072 +/**
9073 + * add or remove a fd to the handled-pool
9074 + */
9075 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx);
9076 +int fdevent_unregister(fdevents *ev, iosocket *sock);
9077  
9078 -int fdevent_poll(fdevents *ev, int timeout_ms);
9079 +/**
9080 + * add a event to a registered fd
9081 + */
9082 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events);
9083 +int fdevent_event_del(fdevents *ev, iosocket *sock);
9084 +
9085 +/**
9086 + * set non-blocking
9087 + */
9088 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock);
9089 +
9090 +fdevent_revents *fdevent_revents_init(void);
9091 +void fdevent_revents_reset(fdevent_revents *revents);
9092 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events);
9093 +void fdevent_revents_free(fdevent_revents *revents);
9094  
9095 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx);
9096 -int fdevent_unregister(fdevents *ev, int fd);
9097 +fdevent_revent *fdevent_revent_init(void);
9098 +void fdevent_revent_free(fdevent_revent *revent);
9099  
9100 -int fdevent_fcntl_set(fdevents *ev, int fd);
9101  
9102 +/**
9103 + * plugin init
9104 + */
9105  int fdevent_select_init(fdevents *ev);
9106  int fdevent_poll_init(fdevents *ev);
9107  int fdevent_linux_rtsig_init(fdevents *ev);
9108 --- ../lighttpd-1.4.11/src/fdevent_freebsd_kqueue.c     2005-09-01 10:46:24.000000000 +0300
9109 +++ lighttpd-1.4.12/src/fdevent_freebsd_kqueue.c        2006-07-16 00:26:03.000000000 +0300
9110 @@ -1,6 +1,5 @@
9111  #include <sys/types.h>
9112  
9113 -#include <unistd.h>
9114  #include <stdlib.h>
9115  #include <stdio.h>
9116  #include <string.h>
9117 @@ -48,7 +47,7 @@
9118  
9119                 return -1;
9120         }
9121 -       
9122 +
9123         return -1;
9124  }
9125  
9126 @@ -65,7 +64,7 @@
9127  
9128         ts.tv_sec  = 0;
9129         ts.tv_nsec = 0;
9130 -       
9131 +
9132         ret = kevent(ev->kq_fd,
9133                      &kev, 1,
9134                      NULL, 0,
9135 @@ -77,7 +76,7 @@
9136  
9137                 return -1;
9138         }
9139 -       
9140 +
9141         if (filter == EVFILT_READ) {
9142                 bitset_set_bit(ev->kq_bevents, fd);
9143         } else {
9144 @@ -124,7 +123,7 @@
9145         } else if (e == EVFILT_WRITE) {
9146                 events |= FDEVENT_OUT;
9147         }
9148 -       
9149 +
9150         e = ev->kq_results[ndx].flags;
9151  
9152         if (e & EV_EOF) {
9153 @@ -152,10 +151,10 @@
9154         if (-1 == (ev->kq_fd = kqueue())) {
9155                 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9156                         __FILE__, __LINE__, strerror(errno));
9157 -               
9158 +
9159                 return -1;
9160         }
9161 -       
9162 +
9163         return 0;
9164  }
9165  
9166 @@ -186,7 +185,7 @@
9167         if (-1 == (ev->kq_fd = kqueue())) {
9168                 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9169                         __FILE__, __LINE__, strerror(errno));
9170 -               
9171 +
9172                 return -1;
9173         }
9174  
9175 --- ../lighttpd-1.4.11/src/fdevent_linux_rtsig.c        2005-11-21 19:56:11.000000000 +0200
9176 +++ lighttpd-1.4.12/src/fdevent_linux_rtsig.c   2006-07-18 13:03:40.000000000 +0300
9177 @@ -1,6 +1,5 @@
9178  #include <sys/types.h>
9179  
9180 -#include <unistd.h>
9181  #include <stdlib.h>
9182  #include <stdio.h>
9183  #include <string.h>
9184 @@ -14,6 +13,8 @@
9185  #include "fdevent.h"
9186  #include "settings.h"
9187  #include "buffer.h"
9188 +#include "sys-process.h"
9189 +#include "log.h"
9190  
9191  #ifdef USE_LINUX_SIGIO
9192  static void fdevent_linux_rtsig_free(fdevents *ev) {
9193 @@ -24,21 +25,21 @@
9194  }
9195  
9196  
9197 -static int fdevent_linux_rtsig_event_del(fdevents *ev, int fde_ndx, int fd) {
9198 -       if (fde_ndx < 0) return -1;
9199 -       
9200 -       if ((size_t)fde_ndx >= ev->used) {
9201 -               fprintf(stderr, "%s.%d: del! out of range %d %zu\n", __FILE__, __LINE__, fde_ndx, ev->used);
9202 +static int fdevent_linux_rtsig_event_del(fdevents *ev, iosocket *sock) {
9203 +       if (sock->fde_ndx < 0) return -1;
9204 +
9205 +       if ((size_t)sock->fde_ndx >= ev->used) {
9206 +               TRACE("del! out of range %d %zu\n", sock->fde_ndx, ev->used);
9207                 SEGFAULT();
9208         }
9209 -       
9210 -       if (ev->pollfds[fde_ndx].fd == fd) {
9211 -               size_t k = fde_ndx;
9212 -               
9213 +
9214 +       if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9215 +               size_t k = sock->fde_ndx;
9216 +
9217                 ev->pollfds[k].fd = -1;
9218  
9219 -               bitset_clear_bit(ev->sigbset, fd);
9220 -               
9221 +               bitset_clear_bit(ev->sigbset, sock->fd);
9222 +
9223                 if (ev->unused.size == 0) {
9224                         ev->unused.size = 16;
9225                         ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
9226 @@ -46,53 +47,54 @@
9227                         ev->unused.size += 16;
9228                         ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
9229                 }
9230 -               
9231 +
9232                 ev->unused.ptr[ev->unused.used++] = k;
9233         } else {
9234 -               fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[fde_ndx].fd, fd);
9235 -               
9236 +               fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[sock->fde_ndx].fd, sock->fd);
9237 +
9238                 SEGFAULT();
9239         }
9240 -       
9241 -       return -1;
9242 +       sock->fde_ndx = -1;
9243 +
9244 +       return 0;
9245  }
9246  
9247  #if 0
9248  static int fdevent_linux_rtsig_event_compress(fdevents *ev) {
9249         size_t j;
9250 -       
9251 +
9252         if (ev->used == 0) return 0;
9253         if (ev->unused.used != 0) return 0;
9254 -       
9255 +
9256         for (j = ev->used - 1; j + 1 > 0; j--) {
9257                 if (ev->pollfds[j].fd == -1) ev->used--;
9258         }
9259 -       
9260 -       
9261 +
9262 +
9263         return 0;
9264  }
9265  #endif
9266  
9267 -static int fdevent_linux_rtsig_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9268 +static int fdevent_linux_rtsig_event_add(fdevents *ev, iosocket *sock, int events) {
9269         /* known index */
9270 -       if (fde_ndx != -1) {
9271 -               if (ev->pollfds[fde_ndx].fd == fd) {
9272 -                       ev->pollfds[fde_ndx].events = events;
9273 -                       
9274 -                       return fde_ndx;
9275 +       if (sock->fde_ndx != -1) {
9276 +               if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9277 +                       ev->pollfds[sock->fde_ndx].events = events;
9278 +
9279 +                       return sock->fde_ndx;
9280                 }
9281 -               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
9282 +               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
9283                 SEGFAULT();
9284         }
9285 -       
9286 +
9287         if (ev->unused.used > 0) {
9288                 int k = ev->unused.ptr[--ev->unused.used];
9289 -               
9290 -               ev->pollfds[k].fd = fd;
9291 +
9292 +               ev->pollfds[k].fd = sock->fd;
9293                 ev->pollfds[k].events = events;
9294  
9295 -               bitset_set_bit(ev->sigbset, fd);
9296 -               
9297 +               bitset_set_bit(ev->sigbset, sock->fd);
9298 +
9299                 return k;
9300         } else {
9301                 if (ev->size == 0) {
9302 @@ -102,12 +104,12 @@
9303                         ev->size += 16;
9304                         ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
9305                 }
9306 -               
9307 -               ev->pollfds[ev->used].fd = fd;
9308 +
9309 +               ev->pollfds[ev->used].fd = sock->fd;
9310                 ev->pollfds[ev->used].events = events;
9311  
9312 -               bitset_set_bit(ev->sigbset, fd);
9313 -       
9314 +               bitset_set_bit(ev->sigbset, sock->fd);
9315 +
9316                 return ev->used++;
9317         }
9318  }
9319 @@ -115,20 +117,20 @@
9320  static int fdevent_linux_rtsig_poll(fdevents *ev, int timeout_ms) {
9321         struct timespec ts;
9322         int r;
9323 -       
9324 +
9325  #if 0
9326         fdevent_linux_rtsig_event_compress(ev);
9327  #endif
9328 -       
9329 +
9330         ev->in_sigio = 1;
9331 -               
9332 +
9333         ts.tv_sec =  timeout_ms / 1000;
9334         ts.tv_nsec = (timeout_ms % 1000) * 1000000;
9335         r = sigtimedwait(&(ev->sigset), &(ev->siginfo), &(ts));
9336 -               
9337 -       if (r == -1) { 
9338 +
9339 +       if (r == -1) {
9340                 if (errno == EAGAIN) return 0;
9341 -               return r; 
9342 +               return r;
9343         } else if (r == SIGIO) {
9344                 struct sigaction act;
9345  
9346 @@ -140,7 +142,7 @@
9347                 /* re-enable the signal queue */
9348                 act.sa_handler = SIG_DFL;
9349                 sigaction(ev->signum, &act, NULL);
9350 -               
9351 +
9352                 ev->in_sigio = 0;
9353                 r = poll(ev->pollfds, ev->used, timeout_ms);
9354  
9355 @@ -156,97 +158,67 @@
9356         }
9357  }
9358  
9359 -static int fdevent_linux_rtsig_event_get_revent(fdevents *ev, size_t ndx) {
9360 +static int fdevent_linux_rtsig_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9361         if (ev->in_sigio == 1) {
9362 -#  if 0
9363 -               if (ev->siginfo.si_band == POLLERR) {
9364 -                       fprintf(stderr, "event: %d %02lx %02x %s\n", ev->siginfo.si_fd, ev->siginfo.si_band, errno, strerror(errno));
9365 -               }
9366 -#  endif               
9367 -               if (ndx != 0) {
9368 -                       fprintf(stderr, "+\n");
9369 -                       return 0;
9370 -               }
9371 -               
9372 -               return ev->siginfo.si_band & 0x3f;
9373 +               /* only one event */
9374 +
9375 +               fdevent_revents_add(revents, ev->siginfo.si_fd, ev->siginfo.si_band & 0x3f);
9376         } else {
9377 -               if (ndx >= ev->used) {
9378 -                       fprintf(stderr, "%s.%d: event: %zu %zu\n", __FILE__, __LINE__, ndx, ev->used);
9379 -                       return 0;
9380 +               size_t ndx;
9381 +
9382 +               for (ndx = 0; ndx < ev->used; ndx++) {
9383 +                       if (ev->pollfds[ndx].revents) {
9384 +                               fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
9385 +                       }
9386                 }
9387 -               return ev->pollfds[ndx].revents;
9388         }
9389 -}
9390  
9391 -static int fdevent_linux_rtsig_event_get_fd(fdevents *ev, size_t ndx) {
9392 -       if (ev->in_sigio == 1) {
9393 -               return ev->siginfo.si_fd;
9394 -       } else {
9395 -               return ev->pollfds[ndx].fd;
9396 -       }
9397 +       return 0;
9398  }
9399  
9400  static int fdevent_linux_rtsig_fcntl_set(fdevents *ev, int fd) {
9401         static pid_t pid = 0;
9402 -       
9403 +
9404         if (pid == 0) pid = getpid();
9405 -       
9406 +
9407         if (-1 == fcntl(fd, F_SETSIG, ev->signum)) return -1;
9408 -       
9409 +
9410         if (-1 == fcntl(fd, F_SETOWN, (int) pid)) return -1;
9411 -       
9412 +
9413         return fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK | O_RDWR);
9414  }
9415  
9416  
9417 -static int fdevent_linux_rtsig_event_next_fdndx(fdevents *ev, int ndx) {
9418 -       if (ev->in_sigio == 1) {
9419 -               if (ndx < 0) return 0;
9420 -               return -1;
9421 -       } else {
9422 -               size_t i;
9423 -               
9424 -               i = (ndx < 0) ? 0 : ndx + 1;
9425 -               for (; i < ev->used; i++) {
9426 -                       if (ev->pollfds[i].revents) break;
9427 -               }
9428 -               
9429 -               return i;
9430 -       }
9431 -}
9432 -
9433  int fdevent_linux_rtsig_init(fdevents *ev) {
9434         ev->type = FDEVENT_HANDLER_LINUX_RTSIG;
9435  #define SET(x) \
9436         ev->x = fdevent_linux_rtsig_##x;
9437 -       
9438 +
9439         SET(free);
9440         SET(poll);
9441 -       
9442 +
9443         SET(event_del);
9444         SET(event_add);
9445 -       
9446 -       SET(event_next_fdndx);
9447 +
9448         SET(fcntl_set);
9449 -       SET(event_get_fd);
9450 -       SET(event_get_revent);
9451 -       
9452 +       SET(get_revents);
9453 +
9454         ev->signum = SIGRTMIN + 1;
9455 -       
9456 +
9457         sigemptyset(&(ev->sigset));
9458         sigaddset(&(ev->sigset), ev->signum);
9459         sigaddset(&(ev->sigset), SIGIO);
9460         if (-1 == sigprocmask(SIG_BLOCK, &(ev->sigset), NULL)) {
9461                 fprintf(stderr, "%s.%d: sigprocmask failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9462                         __FILE__, __LINE__, strerror(errno));
9463 -               
9464 +
9465                 return -1;
9466         }
9467 -       
9468 +
9469         ev->in_sigio = 1;
9470  
9471         ev->sigbset = bitset_init(ev->maxfds);
9472 -       
9473 +
9474         return 0;
9475  }
9476  #else
9477 --- ../lighttpd-1.4.11/src/fdevent_linux_sysepoll.c     2005-09-30 20:29:27.000000000 +0300
9478 +++ lighttpd-1.4.12/src/fdevent_linux_sysepoll.c        2006-07-18 13:03:40.000000000 +0300
9479 @@ -1,6 +1,5 @@
9480  #include <sys/types.h>
9481  
9482 -#include <unistd.h>
9483  #include <stdlib.h>
9484  #include <stdio.h>
9485  #include <string.h>
9486 @@ -11,6 +10,9 @@
9487  #include "fdevent.h"
9488  #include "settings.h"
9489  #include "buffer.h"
9490 +#include "log.h"
9491 +
9492 +#include "sys-files.h"
9493  
9494  #ifdef USE_LINUX_EPOLL
9495  static void fdevent_linux_sysepoll_free(fdevents *ev) {
9496 @@ -18,38 +20,40 @@
9497         free(ev->epoll_events);
9498  }
9499  
9500 -static int fdevent_linux_sysepoll_event_del(fdevents *ev, int fde_ndx, int fd) {
9501 +static int fdevent_linux_sysepoll_event_del(fdevents *ev, iosocket *sock) {
9502         struct epoll_event ep;
9503 -       
9504 -       if (fde_ndx < 0) return -1;
9505 -       
9506 +
9507 +       if (sock->fde_ndx < 0) return -1;
9508 +
9509         memset(&ep, 0, sizeof(ep));
9510 -       
9511 -       ep.data.fd = fd;
9512 +
9513 +       ep.data.fd = sock->fd;
9514         ep.data.ptr = NULL;
9515 -       
9516 -       if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fd, &ep)) {
9517 +
9518 +       if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, sock->fd, &ep)) {
9519                 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
9520 -               
9521 +
9522                 SEGFAULT();
9523 -               
9524 +
9525                 return 0;
9526         }
9527 -       
9528 -       
9529 -       return -1;
9530 +
9531 +       sock->fde_ndx = -1;
9532 +
9533 +       return 0;
9534  }
9535  
9536 -static int fdevent_linux_sysepoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9537 +static int fdevent_linux_sysepoll_event_add(fdevents *ev, iosocket *sock, int events) {
9538         struct epoll_event ep;
9539         int add = 0;
9540 -       
9541 -       if (fde_ndx == -1) add = 1;
9542 -       
9543 +
9544 +       /* a new fd */
9545 +       if (sock->fde_ndx == -1) add = 1;
9546 +
9547         memset(&ep, 0, sizeof(ep));
9548 -       
9549 +
9550         ep.events = 0;
9551 -       
9552 +
9553         if (events & FDEVENT_IN)  ep.events |= EPOLLIN;
9554         if (events & FDEVENT_OUT) ep.events |= EPOLLOUT;
9555  
9556 @@ -60,73 +64,61 @@
9557          * sent.
9558          *
9559          */
9560 -       
9561 +
9562         ep.events |= EPOLLERR | EPOLLHUP /* | EPOLLET */;
9563 -       
9564 +
9565         ep.data.ptr = NULL;
9566 -       ep.data.fd = fd;
9567 -       
9568 -       if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &ep)) {
9569 +       ep.data.fd = sock->fd;
9570 +
9571 +       if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, sock->fd, &ep)) {
9572                 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
9573 -               
9574 +
9575                 SEGFAULT();
9576 -               
9577 +
9578                 return 0;
9579         }
9580 -       
9581 -       return fd;
9582 +
9583 +       sock->fde_ndx = sock->fd;
9584 +
9585 +       return 0;
9586  }
9587  
9588  static int fdevent_linux_sysepoll_poll(fdevents *ev, int timeout_ms) {
9589         return epoll_wait(ev->epoll_fd, ev->epoll_events, ev->maxfds, timeout_ms);
9590  }
9591  
9592 -static int fdevent_linux_sysepoll_event_get_revent(fdevents *ev, size_t ndx) {
9593 -       int events = 0, e;
9594 -       
9595 -       e = ev->epoll_events[ndx].events;
9596 -       if (e & EPOLLIN) events |= FDEVENT_IN;
9597 -       if (e & EPOLLOUT) events |= FDEVENT_OUT;
9598 -       if (e & EPOLLERR) events |= FDEVENT_ERR;
9599 -       if (e & EPOLLHUP) events |= FDEVENT_HUP;
9600 -       if (e & EPOLLPRI) events |= FDEVENT_PRI;
9601 -       
9602 -       return e;
9603 -}
9604 -
9605 -static int fdevent_linux_sysepoll_event_get_fd(fdevents *ev, size_t ndx) {
9606 -# if 0
9607 -       fprintf(stderr, "%s.%d: %d, %d\n", __FILE__, __LINE__, ndx, ev->epoll_events[ndx].data.fd);
9608 -# endif
9609 -       
9610 -       return ev->epoll_events[ndx].data.fd;
9611 -}
9612 -
9613 -static int fdevent_linux_sysepoll_event_next_fdndx(fdevents *ev, int ndx) {
9614 -       size_t i;
9615 -       
9616 -       UNUSED(ev);
9617 +static int fdevent_linux_sysepoll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9618 +       size_t ndx;
9619 +
9620 +       for (ndx = 0; ndx < event_count; ndx++) {
9621 +               int events = 0, e;
9622 +
9623 +               e = ev->epoll_events[ndx].events;
9624 +               if (e & EPOLLIN) events |= FDEVENT_IN;
9625 +               if (e & EPOLLOUT) events |= FDEVENT_OUT;
9626 +               if (e & EPOLLERR) events |= FDEVENT_ERR;
9627 +               if (e & EPOLLHUP) events |= FDEVENT_HUP;
9628 +               if (e & EPOLLPRI) events |= FDEVENT_PRI;
9629  
9630 -       i = (ndx < 0) ? 0 : ndx + 1;
9631 -       
9632 -       return i;
9633 +               fdevent_revents_add(revents, ev->epoll_events[ndx].data.fd, e);
9634 +       }
9635 +
9636 +       return 0;
9637  }
9638  
9639  int fdevent_linux_sysepoll_init(fdevents *ev) {
9640         ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
9641  #define SET(x) \
9642         ev->x = fdevent_linux_sysepoll_##x;
9643 -       
9644 +
9645         SET(free);
9646         SET(poll);
9647 -       
9648 +
9649         SET(event_del);
9650         SET(event_add);
9651 -       
9652 -       SET(event_next_fdndx);
9653 -       SET(event_get_fd);
9654 -       SET(event_get_revent);
9655 -       
9656 +
9657 +       SET(get_revents);
9658 +
9659         if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) {
9660                 fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9661                         __FILE__, __LINE__, strerror(errno));
9662 @@ -154,7 +146,7 @@
9663  
9664         fprintf(stderr, "%s.%d: linux-sysepoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
9665                 __FILE__, __LINE__);
9666 -       
9667 +
9668         return -1;
9669  }
9670  #endif
9671 --- ../lighttpd-1.4.11/src/fdevent_poll.c       2005-11-18 13:59:16.000000000 +0200
9672 +++ lighttpd-1.4.12/src/fdevent_poll.c  2006-07-18 13:03:40.000000000 +0300
9673 @@ -1,6 +1,5 @@
9674  #include <sys/types.h>
9675  
9676 -#include <unistd.h>
9677  #include <stdlib.h>
9678  #include <stdio.h>
9679  #include <string.h>
9680 @@ -11,6 +10,7 @@
9681  #include "fdevent.h"
9682  #include "settings.h"
9683  #include "buffer.h"
9684 +#include "log.h"
9685  
9686  #ifdef USE_POLL
9687  static void fdevent_poll_free(fdevents *ev) {
9688 @@ -18,21 +18,21 @@
9689         if (ev->unused.ptr) free(ev->unused.ptr);
9690  }
9691  
9692 -static int fdevent_poll_event_del(fdevents *ev, int fde_ndx, int fd) {
9693 -       if (fde_ndx < 0) return -1;
9694 -       
9695 -       if ((size_t)fde_ndx >= ev->used) {
9696 -               fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, fde_ndx, ev->used);
9697 +static int fdevent_poll_event_del(fdevents *ev, iosocket *sock) {
9698 +       if (sock->fde_ndx < 0) return -1;
9699 +
9700 +       if ((size_t)sock->fde_ndx >= ev->used) {
9701 +               fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, sock->fde_ndx, ev->used);
9702                 SEGFAULT();
9703         }
9704 -       
9705 -       if (ev->pollfds[fde_ndx].fd == fd) {
9706 -               size_t k = fde_ndx;
9707 -               
9708 +
9709 +       if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9710 +               size_t k = sock->fde_ndx;
9711 +
9712                 ev->pollfds[k].fd = -1;
9713                 /* ev->pollfds[k].events = 0; */
9714                 /* ev->pollfds[k].revents = 0; */
9715 -               
9716 +
9717                 if (ev->unused.size == 0) {
9718                         ev->unused.size = 16;
9719                         ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
9720 @@ -40,48 +40,51 @@
9721                         ev->unused.size += 16;
9722                         ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
9723                 }
9724 -               
9725 +
9726                 ev->unused.ptr[ev->unused.used++] = k;
9727         } else {
9728                 SEGFAULT();
9729         }
9730 -       
9731 -       return -1;
9732 +
9733 +       sock->fde_ndx = -1;
9734 +
9735 +       return 0;
9736  }
9737  
9738  #if 0
9739  static int fdevent_poll_event_compress(fdevents *ev) {
9740         size_t j;
9741 -       
9742 +
9743         if (ev->used == 0) return 0;
9744         if (ev->unused.used != 0) return 0;
9745 -       
9746 +
9747         for (j = ev->used - 1; j + 1 > 0 && ev->pollfds[j].fd == -1; j--) ev->used--;
9748 -       
9749 +
9750         return 0;
9751  }
9752  #endif
9753  
9754 -static int fdevent_poll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9755 -       /* known index */
9756 -       
9757 -       if (fde_ndx != -1) {
9758 -               if (ev->pollfds[fde_ndx].fd == fd) {
9759 -                       ev->pollfds[fde_ndx].events = events;
9760 -                       
9761 -                       return fde_ndx;
9762 +static int fdevent_poll_event_add(fdevents *ev, iosocket *sock, int events) {
9763 +       if (sock->fde_ndx != -1) {
9764 +               /* this fd was already added, just change the requested events */
9765 +
9766 +               if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9767 +                       ev->pollfds[sock->fde_ndx].events = events;
9768 +
9769 +                       return sock->fde_ndx;
9770                 }
9771 -               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
9772 +               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
9773                 SEGFAULT();
9774         }
9775 -       
9776 +
9777         if (ev->unused.used > 0) {
9778                 int k = ev->unused.ptr[--ev->unused.used];
9779 -               
9780 -               ev->pollfds[k].fd = fd;
9781 +
9782 +               ev->pollfds[k].fd = sock->fd;
9783                 ev->pollfds[k].events = events;
9784 -               
9785 -               return k;
9786 +
9787 +               sock->fde_ndx = k;
9788 +
9789         } else {
9790                 if (ev->size == 0) {
9791                         ev->size = 16;
9792 @@ -90,12 +93,13 @@
9793                         ev->size += 16;
9794                         ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
9795                 }
9796 -               
9797 -               ev->pollfds[ev->used].fd = fd;
9798 +
9799 +               ev->pollfds[ev->used].fd = sock->fd;
9800                 ev->pollfds[ev->used].events = events;
9801 -               
9802 -               return ev->used++;
9803 +
9804 +               sock->fde_ndx = ev->used++;
9805         }
9806 +       return 0;
9807  }
9808  
9809  static int fdevent_poll_poll(fdevents *ev, int timeout_ms) {
9810 @@ -105,71 +109,38 @@
9811         return poll(ev->pollfds, ev->used, timeout_ms);
9812  }
9813  
9814 -static int fdevent_poll_event_get_revent(fdevents *ev, size_t ndx) {
9815 -       int r, poll_r;
9816 -       if (ndx >= ev->used) {
9817 -               fprintf(stderr, "%s.%d: dying because: event: %zd >= %zd\n", __FILE__, __LINE__, ndx, ev->used);
9818 -               
9819 -               SEGFAULT();
9820 -               
9821 -               return 0;
9822 -       }
9823 -       
9824 -       if (ev->pollfds[ndx].revents & POLLNVAL) {
9825 -               /* should never happen */
9826 -               SEGFAULT();
9827 -       }
9828 +static int fdevent_poll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9829 +       size_t ndx;
9830  
9831 -       r = 0;
9832 -       poll_r = ev->pollfds[ndx].revents;
9833 +       for (ndx = 0; ndx < ev->used; ndx++) {
9834 +               if (ev->pollfds[ndx].revents) {
9835 +                       if (ev->pollfds[ndx].revents & POLLNVAL) {
9836 +                               /* should never happen */
9837 +                               SEGFAULT();
9838 +                       }
9839  
9840 -       /* map POLL* to FDEVEN_* */
9841 -
9842 -       if (poll_r & POLLIN) r |= FDEVENT_IN;
9843 -       if (poll_r & POLLOUT) r |= FDEVENT_OUT;
9844 -       if (poll_r & POLLERR) r |= FDEVENT_ERR;
9845 -       if (poll_r & POLLHUP) r |= FDEVENT_HUP;
9846 -       if (poll_r & POLLNVAL) r |= FDEVENT_NVAL;
9847 -       if (poll_r & POLLPRI) r |= FDEVENT_PRI;
9848 -       
9849 -       return ev->pollfds[ndx].revents;
9850 -}
9851 -
9852 -static int fdevent_poll_event_get_fd(fdevents *ev, size_t ndx) {
9853 -       return ev->pollfds[ndx].fd;
9854 -}
9855 -
9856 -static int fdevent_poll_event_next_fdndx(fdevents *ev, int ndx) {
9857 -       size_t i;
9858 -       
9859 -       i = (ndx < 0) ? 0 : ndx + 1;
9860 -       for (; i < ev->used; i++) {
9861 -               if (ev->pollfds[i].revents) break;
9862 +                       fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
9863 +               }
9864         }
9865 -       
9866 -       return i;
9867 +
9868 +       return 0;
9869  }
9870  
9871  int fdevent_poll_init(fdevents *ev) {
9872         ev->type = FDEVENT_HANDLER_POLL;
9873  #define SET(x) \
9874         ev->x = fdevent_poll_##x;
9875 -       
9876 +
9877         SET(free);
9878         SET(poll);
9879 -       
9880 +
9881         SET(event_del);
9882         SET(event_add);
9883 -       
9884 -       SET(event_next_fdndx);
9885 -       SET(event_get_fd);
9886 -       SET(event_get_revent);
9887 -       
9888 -       return 0;
9889 -}
9890 -
9891  
9892 +       SET(get_revents);
9893  
9894 +       return 0;
9895 +}
9896  
9897  #else
9898  int fdevent_poll_init(fdevents *ev) {
9899 --- ../lighttpd-1.4.11/src/fdevent_select.c     2005-08-31 11:12:46.000000000 +0300
9900 +++ lighttpd-1.4.12/src/fdevent_select.c        2006-07-18 13:03:40.000000000 +0300
9901 @@ -1,18 +1,19 @@
9902 -#include <sys/time.h>
9903  #include <sys/types.h>
9904  
9905 -#include <unistd.h>
9906  #include <stdlib.h>
9907  #include <string.h>
9908  #include <errno.h>
9909  #include <signal.h>
9910  #include <fcntl.h>
9911  #include <assert.h>
9912 +#include <stdio.h>
9913  
9914  #include "fdevent.h"
9915  #include "settings.h"
9916  #include "buffer.h"
9917  
9918 +#include "sys-socket.h"
9919 +
9920  #ifdef USE_SELECT
9921  
9922  static int fdevent_select_reset(fdevents *ev) {
9923 @@ -24,101 +25,98 @@
9924         return 0;
9925  }
9926  
9927 -static int fdevent_select_event_del(fdevents *ev, int fde_ndx, int fd) {
9928 -       if (fde_ndx < 0) return -1;
9929 +static int fdevent_select_event_del(fdevents *ev, iosocket *sock) {
9930 +       if (sock->fde_ndx < 0) return -1;
9931  
9932 -       FD_CLR(fd, &(ev->select_set_read));
9933 -       FD_CLR(fd, &(ev->select_set_write));
9934 -       FD_CLR(fd, &(ev->select_set_error));
9935 +       FD_CLR(sock->fd, &(ev->select_set_read));
9936 +       FD_CLR(sock->fd, &(ev->select_set_write));
9937 +       FD_CLR(sock->fd, &(ev->select_set_error));
9938  
9939 -       return -1;
9940 -}
9941 +       /* mark the fdevent as deleted */
9942 +       sock->fde_ndx = -1;
9943  
9944 -static int fdevent_select_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9945 -       UNUSED(fde_ndx);
9946 +       return 0;
9947 +}
9948  
9949 +static int fdevent_select_event_add(fdevents *ev, iosocket *sock, int events) {
9950         /* we should be protected by max-fds, but you never know */
9951 -       assert(fd < FD_SETSIZE);
9952 +#ifndef _WIN32
9953 +       assert(sock->fd < FD_SETSIZE);
9954 +#endif
9955  
9956         if (events & FDEVENT_IN) {
9957 -               FD_SET(fd, &(ev->select_set_read));
9958 -               FD_CLR(fd, &(ev->select_set_write));
9959 +               FD_SET(sock->fd, &(ev->select_set_read));
9960 +               FD_CLR(sock->fd, &(ev->select_set_write));
9961         }
9962         if (events & FDEVENT_OUT) {
9963 -               FD_CLR(fd, &(ev->select_set_read));
9964 -               FD_SET(fd, &(ev->select_set_write));
9965 +               FD_CLR(sock->fd, &(ev->select_set_read));
9966 +               FD_SET(sock->fd, &(ev->select_set_write));
9967         }
9968 -       FD_SET(fd, &(ev->select_set_error));
9969 -       
9970 -       if (fd > ev->select_max_fd) ev->select_max_fd = fd;
9971 -       
9972 -       return fd;
9973 +       FD_SET(sock->fd, &(ev->select_set_error));
9974 +
9975 +       /* we need this for the poll */
9976 +       if (sock->fd > ev->select_max_fd) ev->select_max_fd = sock->fd;
9977 +
9978 +       /* mark fd as added */
9979 +       sock->fde_ndx = sock->fd;
9980 +
9981 +       return 0;
9982  }
9983  
9984  static int fdevent_select_poll(fdevents *ev, int timeout_ms) {
9985         struct timeval tv;
9986 -       
9987 +
9988         tv.tv_sec =  timeout_ms / 1000;
9989         tv.tv_usec = (timeout_ms % 1000) * 1000;
9990 -       
9991 +
9992         ev->select_read = ev->select_set_read;
9993         ev->select_write = ev->select_set_write;
9994         ev->select_error = ev->select_set_error;
9995 -       
9996 +
9997         return select(ev->select_max_fd + 1, &(ev->select_read), &(ev->select_write), &(ev->select_error), &tv);
9998  }
9999  
10000 -static int fdevent_select_event_get_revent(fdevents *ev, size_t ndx) {
10001 -       int revents = 0;
10002 -       
10003 -       if (FD_ISSET(ndx, &(ev->select_read))) {
10004 -               revents |= FDEVENT_IN;
10005 +/**
10006 + * scan the fdset for events 
10007 + */
10008 +static int fdevent_select_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
10009 +
10010 +       int ndx = 0;
10011 +
10012 +       for (ndx = 0; ndx < ev->select_max_fd; ndx++) {
10013 +               int events = 0;
10014 +
10015 +               if (FD_ISSET(ndx, &(ev->select_read))) {
10016 +                       events |= FDEVENT_IN;
10017 +               }
10018 +               if (FD_ISSET(ndx, &(ev->select_write))) {
10019 +                       events |= FDEVENT_OUT;
10020 +               }
10021 +               if (FD_ISSET(ndx, &(ev->select_error))) {
10022 +                       events |= FDEVENT_ERR;
10023 +               }
10024 +
10025 +               if (events) {
10026 +                       fdevent_revents_add(revents, ndx, events);
10027 +               }
10028         }
10029 -       if (FD_ISSET(ndx, &(ev->select_write))) {
10030 -               revents |= FDEVENT_OUT;
10031 -       }
10032 -       if (FD_ISSET(ndx, &(ev->select_error))) {
10033 -               revents |= FDEVENT_ERR;
10034 -       }
10035 -       
10036 -       return revents;
10037 -}
10038 -
10039 -static int fdevent_select_event_get_fd(fdevents *ev, size_t ndx) {
10040 -       UNUSED(ev);
10041 -
10042 -       return ndx;
10043 -}
10044  
10045 -static int fdevent_select_event_next_fdndx(fdevents *ev, int ndx) {
10046 -       int i;
10047 -       
10048 -       i = (ndx < 0) ? 0 : ndx + 1;
10049 -       
10050 -       for (; i < ev->select_max_fd + 1; i++) {
10051 -               if (FD_ISSET(i, &(ev->select_read))) break;
10052 -               if (FD_ISSET(i, &(ev->select_write))) break;
10053 -               if (FD_ISSET(i, &(ev->select_error))) break;
10054 -       }
10055 -       
10056 -       return i;
10057 +       return 0;
10058  }
10059  
10060  int fdevent_select_init(fdevents *ev) {
10061         ev->type = FDEVENT_HANDLER_SELECT;
10062  #define SET(x) \
10063         ev->x = fdevent_select_##x;
10064 -       
10065 +
10066         SET(reset);
10067         SET(poll);
10068 -       
10069 +
10070         SET(event_del);
10071         SET(event_add);
10072 -       
10073 -       SET(event_next_fdndx);
10074 -       SET(event_get_fd);
10075 -       SET(event_get_revent);
10076 -       
10077 +
10078 +       SET(get_revents);
10079 +
10080         return 0;
10081  }
10082  
10083 --- ../lighttpd-1.4.11/src/fdevent_solaris_devpoll.c    2005-09-01 10:45:26.000000000 +0300
10084 +++ lighttpd-1.4.12/src/fdevent_solaris_devpoll.c       2006-07-16 00:26:03.000000000 +0300
10085 @@ -1,6 +1,5 @@
10086  #include <sys/types.h>
10087  
10088 -#include <unistd.h>
10089  #include <stdlib.h>
10090  #include <stdio.h>
10091  #include <string.h>
10092 @@ -23,55 +22,55 @@
10093  
10094  static int fdevent_solaris_devpoll_event_del(fdevents *ev, int fde_ndx, int fd) {
10095         struct pollfd pfd;
10096 -               
10097 +
10098         if (fde_ndx < 0) return -1;
10099 -       
10100 +
10101         pfd.fd = fd;
10102         pfd.events = POLLREMOVE;
10103         pfd.revents = 0;
10104 -       
10105 +
10106         if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
10107 -               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n", 
10108 -                       __FILE__, __LINE__, 
10109 +               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10110 +                       __FILE__, __LINE__,
10111                         fd, strerror(errno));
10112 -               
10113 +
10114                 return -1;
10115         }
10116 -       
10117 +
10118         return -1;
10119  }
10120  
10121  static int fdevent_solaris_devpoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
10122         struct pollfd pfd;
10123         int add = 0;
10124 -               
10125 +
10126         if (fde_ndx == -1) add = 1;
10127 -       
10128 +
10129         pfd.fd = fd;
10130         pfd.events = events;
10131         pfd.revents = 0;
10132 -       
10133 +
10134         if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
10135 -               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n", 
10136 -                       __FILE__, __LINE__, 
10137 +               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10138 +                       __FILE__, __LINE__,
10139                         fd, strerror(errno));
10140 -               
10141 +
10142                 return -1;
10143         }
10144 -       
10145 +
10146         return fd;
10147  }
10148  
10149  static int fdevent_solaris_devpoll_poll(fdevents *ev, int timeout_ms) {
10150         struct dvpoll dopoll;
10151         int ret;
10152 -       
10153 +
10154         dopoll.dp_timeout = timeout_ms;
10155         dopoll.dp_nfds = ev->maxfds;
10156         dopoll.dp_fds = ev->devpollfds;
10157 -       
10158 +
10159         ret = ioctl(ev->devpoll_fd, DP_POLL, &dopoll);
10160 -       
10161 +
10162         return ret;
10163  }
10164  
10165 @@ -85,11 +84,11 @@
10166  
10167  static int fdevent_solaris_devpoll_event_next_fdndx(fdevents *ev, int last_ndx) {
10168         size_t i;
10169 -       
10170 +
10171         UNUSED(ev);
10172  
10173         i = (last_ndx < 0) ? 0 : last_ndx + 1;
10174 -       
10175 +
10176         return i;
10177  }
10178  
10179 @@ -117,20 +116,20 @@
10180         ev->type = FDEVENT_HANDLER_SOLARIS_DEVPOLL;
10181  #define SET(x) \
10182         ev->x = fdevent_solaris_devpoll_##x;
10183 -       
10184 +
10185         SET(free);
10186         SET(poll);
10187         SET(reset);
10188 -       
10189 +
10190         SET(event_del);
10191         SET(event_add);
10192 -       
10193 +
10194         SET(event_next_fdndx);
10195         SET(event_get_fd);
10196         SET(event_get_revent);
10197 -       
10198 +
10199         ev->devpollfds = malloc(sizeof(*ev->devpollfds) * ev->maxfds);
10200 -       
10201 +
10202         if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
10203                 fprintf(stderr, "%s.%d: opening /dev/poll failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
10204                         __FILE__, __LINE__, strerror(errno));
10205 @@ -152,7 +151,7 @@
10206  
10207         fprintf(stderr, "%s.%d: solaris-devpoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
10208                         __FILE__, __LINE__);
10209 -       
10210 +
10211         return -1;
10212  }
10213  #endif
10214 --- ../lighttpd-1.4.11/src/http-header-glue.c   2006-02-08 15:31:36.000000000 +0200
10215 +++ lighttpd-1.4.12/src/http-header-glue.c      2006-07-18 13:03:40.000000000 +0300
10216 @@ -45,20 +45,20 @@
10217  #   ifdef HAVE_STRUCT_SOCKADDR_STORAGE
10218  static size_t get_sa_len(const struct sockaddr *addr) {
10219         switch (addr->sa_family) {
10220 -               
10221 +
10222  #    ifdef AF_INET
10223         case AF_INET:
10224                 return (sizeof (struct sockaddr_in));
10225  #    endif
10226 -               
10227 +
10228  #    ifdef AF_INET6
10229         case AF_INET6:
10230                 return (sizeof (struct sockaddr_in6));
10231  #    endif
10232 -               
10233 +
10234         default:
10235                 return (sizeof (struct sockaddr));
10236 -               
10237 +
10238         }
10239  }
10240  #    define SA_LEN(addr)   (get_sa_len(addr))
10241 @@ -74,7 +74,7 @@
10242  
10243  int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
10244         data_string *ds;
10245 -       
10246 +
10247         UNUSED(srv);
10248  
10249         if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
10250 @@ -82,32 +82,32 @@
10251         }
10252         buffer_copy_string_len(ds->key, key, keylen);
10253         buffer_copy_string_len(ds->value, value, vallen);
10254 -       
10255 +
10256         array_insert_unique(con->response.headers, (data_unset *)ds);
10257 -       
10258 +
10259         return 0;
10260  }
10261  
10262  int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
10263         data_string *ds;
10264 -       
10265 +
10266         UNUSED(srv);
10267  
10268         /* if there already is a key by this name overwrite the value */
10269         if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key))) {
10270                 buffer_copy_string(ds->value, value);
10271 -               
10272 +
10273                 return 0;
10274         }
10275 -       
10276 +
10277         return response_header_insert(srv, con, key, keylen, value, vallen);
10278  }
10279  
10280  int http_response_redirect_to_directory(server *srv, connection *con) {
10281         buffer *o;
10282 -       
10283 +
10284         o = buffer_init();
10285 -       
10286 +
10287         if (con->conf.is_ssl) {
10288                 buffer_copy_string(o, "https://");
10289         } else {
10290 @@ -123,36 +123,36 @@
10291  #endif
10292                 sock_addr our_addr;
10293                 socklen_t our_addr_len;
10294 -               
10295 +
10296                 our_addr_len = sizeof(our_addr);
10297 -               
10298 -               if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
10299 +
10300 +               if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
10301                         con->http_status = 500;
10302 -                       
10303 +
10304                         log_error_write(srv, __FILE__, __LINE__, "ss",
10305                                         "can't get sockname", strerror(errno));
10306 -                       
10307 +
10308                         buffer_free(o);
10309                         return 0;
10310                 }
10311 -               
10312 -               
10313 +
10314 +
10315                 /* Lookup name: secondly try to get hostname for bind address */
10316                 switch(our_addr.plain.sa_family) {
10317  #ifdef HAVE_IPV6
10318                 case AF_INET6:
10319 -                       if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6), 
10320 -                                            SA_LEN((const struct sockaddr *)&our_addr.ipv6), 
10321 +                       if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
10322 +                                            SA_LEN((const struct sockaddr *)&our_addr.ipv6),
10323                                              hbuf, sizeof(hbuf), NULL, 0, 0)) {
10324 -                               
10325 +
10326                                 char dst[INET6_ADDRSTRLEN];
10327 -                               
10328 +
10329                                 log_error_write(srv, __FILE__, __LINE__,
10330                                                 "SSSS", "NOTICE: getnameinfo failed: ",
10331                                                 strerror(errno), ", using ip-address instead");
10332 -                               
10333 -                               buffer_append_string(o, 
10334 -                                                    inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr, 
10335 +
10336 +                               buffer_append_string(o,
10337 +                                                    inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
10338                                                                dst, sizeof(dst)));
10339                         } else {
10340                                 buffer_append_string(o, hbuf);
10341 @@ -164,7 +164,7 @@
10342                                 log_error_write(srv, __FILE__, __LINE__,
10343                                                 "SdSS", "NOTICE: gethostbyaddr failed: ",
10344                                                 h_errno, ", using ip-address instead");
10345 -                               
10346 +
10347                                 buffer_append_string(o, inet_ntoa(our_addr.ipv4.sin_addr));
10348                         } else {
10349                                 buffer_append_string(o, he->h_name);
10350 @@ -173,12 +173,12 @@
10351                 default:
10352                         log_error_write(srv, __FILE__, __LINE__,
10353                                         "S", "ERROR: unsupported address-type");
10354 -                       
10355 +
10356                         buffer_free(o);
10357                         return -1;
10358                 }
10359 -               
10360 -               if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) || 
10361 +
10362 +               if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) ||
10363                       (con->conf.is_ssl == 1 && srv->srvconf.port == 443))) {
10364                         buffer_append_string(o, ":");
10365                         buffer_append_long(o, srv->srvconf.port);
10366 @@ -190,41 +190,41 @@
10367                 buffer_append_string(o, "?");
10368                 buffer_append_string_buffer(o, con->uri.query);
10369         }
10370 -       
10371 +
10372         response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(o));
10373 -       
10374 +
10375         con->http_status = 301;
10376         con->file_finished = 1;
10377 -       
10378 +
10379         buffer_free(o);
10380 -       
10381 +
10382         return 0;
10383  }
10384  
10385  buffer * strftime_cache_get(server *srv, time_t last_mod) {
10386         struct tm *tm;
10387         size_t i;
10388 -               
10389 +
10390         for (i = 0; i < FILE_CACHE_MAX; i++) {
10391                 /* found cache-entry */
10392                 if (srv->mtime_cache[i].mtime == last_mod) return srv->mtime_cache[i].str;
10393 -                               
10394 +
10395                 /* found empty slot */
10396                 if (srv->mtime_cache[i].mtime == 0) break;
10397         }
10398 -       
10399 +
10400         if (i == FILE_CACHE_MAX) {
10401                 i = 0;
10402         }
10403 -               
10404 +
10405         srv->mtime_cache[i].mtime = last_mod;
10406         buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
10407         tm = gmtime(&(srv->mtime_cache[i].mtime));
10408 -       srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr, 
10409 +       srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
10410                                                  srv->mtime_cache[i].str->size - 1,
10411                                                  "%a, %d %b %Y %H:%M:%S GMT", tm);
10412         srv->mtime_cache[i].str->used++;
10413 -       
10414 +
10415         return srv->mtime_cache[i].str;
10416  }
10417  
10418 @@ -239,56 +239,60 @@
10419          *    request. That is, if no entity tags match, then the server MUST NOT
10420          *    return a 304 (Not Modified) response.
10421          */
10422 -       
10423 +
10424         /* last-modified handling */
10425         if (con->request.http_if_none_match) {
10426                 if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
10427 -                       if (con->request.http_method == HTTP_METHOD_GET || 
10428 +                       if (con->request.http_method == HTTP_METHOD_GET ||
10429                             con->request.http_method == HTTP_METHOD_HEAD) {
10430 -                               
10431 +
10432                                 /* check if etag + last-modified */
10433                                 if (con->request.http_if_modified_since) {
10434                                         size_t used_len;
10435                                         char *semicolon;
10436 -                                       
10437 +
10438                                         if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
10439                                                 used_len = strlen(con->request.http_if_modified_since);
10440                                         } else {
10441                                                 used_len = semicolon - con->request.http_if_modified_since;
10442                                         }
10443 -                                       
10444 +
10445                                         if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
10446                                                 con->http_status = 304;
10447                                                 return HANDLER_FINISHED;
10448                                         } else {
10449 +#ifdef HAVE_STRPTIME
10450                                                 char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
10451 +                                               time_t t_header, t_file;
10452 +                                               struct tm tm;
10453  
10454 -                                               /* convert to timestamp */
10455 -                                               if (used_len < sizeof(buf)) {
10456 -                                                       time_t t_header, t_file;
10457 -                                                       struct tm tm;
10458 -                                                       
10459 -                                                       strncpy(buf, con->request.http_if_modified_since, used_len);
10460 -                                                       buf[used_len] = '\0';
10461 -                                                       
10462 -                                                       strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10463 -                                                       t_header = mktime(&tm);
10464 -                                                       
10465 -                                                       strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10466 -                                                       t_file = mktime(&tm);
10467 -
10468 -                                                       if (t_file > t_header) {
10469 -                                                               con->http_status = 304;
10470 -                                                               return HANDLER_FINISHED;
10471 -                                                       }
10472 -                                               } else {
10473 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssdd", 
10474 -                                                                       "DEBUG: Last-Modified check failed as the received timestamp was too long:", 
10475 +                                               /* check if we can safely copy the string */
10476 +                                               if (used_len >= sizeof(buf)) {
10477 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssdd",
10478 +                                                                       "DEBUG: Last-Modified check failed as the received timestamp was too long:",
10479                                                                         con->request.http_if_modified_since, used_len, sizeof(buf) - 1);
10480 -                                                       
10481 +
10482                                                         con->http_status = 412;
10483                                                         return HANDLER_FINISHED;
10484                                                 }
10485 +
10486 +
10487 +                                               strncpy(buf, con->request.http_if_modified_since, used_len);
10488 +                                               buf[used_len] = '\0';
10489 +
10490 +                                               strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10491 +                                               t_header = mktime(&tm);
10492 +
10493 +                                               strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10494 +                                               t_file = mktime(&tm);
10495 +
10496 +                                               if (t_file > t_header) return HANDLER_GO_ON;
10497 +
10498 +                                               con->http_status = 304;
10499 +                                               return HANDLER_FINISHED;
10500 +#else
10501 +                        return HANDLER_GO_ON;
10502 +#endif
10503                                         }
10504                                 } else {
10505                                         con->http_status = 304;
10506 @@ -302,16 +306,41 @@
10507         } else if (con->request.http_if_modified_since) {
10508                 size_t used_len;
10509                 char *semicolon;
10510 -               
10511 +
10512                 if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
10513                         used_len = strlen(con->request.http_if_modified_since);
10514                 } else {
10515                         used_len = semicolon - con->request.http_if_modified_since;
10516                 }
10517 -               
10518 +
10519                 if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
10520                         con->http_status = 304;
10521                         return HANDLER_FINISHED;
10522 +               } else {
10523 +#ifdef HAVE_STRPTIME
10524 +                       char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
10525 +                       time_t t_header, t_file;
10526 +                       struct tm tm;
10527 +
10528 +                       /* convert to timestamp */
10529 +                       if (used_len >= sizeof(buf)) return HANDLER_GO_ON;
10530 +
10531 +                       strncpy(buf, con->request.http_if_modified_since, used_len);
10532 +                       buf[used_len] = '\0';
10533 +
10534 +                       strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10535 +                       t_header = mktime(&tm);
10536 +
10537 +                       strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10538 +                       t_file = mktime(&tm);
10539 +
10540 +                       if (t_file > t_header) return HANDLER_GO_ON;
10541 +
10542 +                       con->http_status = 304;
10543 +                       return HANDLER_FINISHED;
10544 +#else
10545 +            return HANDLER_GO_ON;
10546 +#endif
10547                 }
10548         }
10549  
10550 --- ../lighttpd-1.4.11/src/http_auth.c  2006-02-01 13:02:52.000000000 +0200
10551 +++ lighttpd-1.4.12/src/http_auth.c     2006-07-18 13:03:40.000000000 +0300
10552 @@ -22,7 +22,6 @@
10553  #include <string.h>
10554  #include <time.h>
10555  #include <errno.h>
10556 -#include <unistd.h>
10557  #include <ctype.h>
10558  
10559  #include "server.h"
10560 @@ -31,23 +30,14 @@
10561  #include "http_auth_digest.h"
10562  #include "stream.h"
10563  
10564 +#include "sys-strings.h"
10565 +
10566  #ifdef USE_OPENSSL
10567  # include <openssl/md5.h>
10568  #else
10569  # include "md5.h"
10570  #endif
10571  
10572 -
10573 -#ifdef USE_PAM
10574 -#include <security/pam_appl.h>
10575 -#include <security/pam_misc.h>
10576 -
10577 -static struct pam_conv conv = {
10578 -       misc_conv,
10579 -               NULL
10580 -};
10581 -#endif
10582 -
10583  handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
10584  
10585  static const char base64_pad = '=';
10586 @@ -75,25 +65,25 @@
10587         unsigned char *result;
10588         int ch, j = 0, k;
10589         size_t i;
10590 -       
10591 +
10592         size_t in_len = strlen(in);
10593 -       
10594 +
10595         buffer_prepare_copy(out, in_len);
10596 -       
10597 +
10598         result = (unsigned char *)out->ptr;
10599 -       
10600 +
10601         ch = in[0];
10602         /* run through the whole string, converting as we go */
10603         for (i = 0; i < in_len; i++) {
10604                 ch = in[i];
10605 -               
10606 +
10607                 if (ch == '\0') break;
10608 -               
10609 +
10610                 if (ch == base64_pad) break;
10611 -               
10612 +
10613                 ch = base64_reverse_table[ch];
10614                 if (ch < 0) continue;
10615 -               
10616 +
10617                 switch(i % 4) {
10618                 case 0:
10619                         result[j] = ch << 2;
10620 @@ -125,168 +115,168 @@
10621                 }
10622         }
10623         result[k] = '\0';
10624 -       
10625 +
10626         out->used = k;
10627 -       
10628 +
10629         return result;
10630  }
10631  
10632  static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *username, buffer *realm, buffer *password) {
10633         int ret = -1;
10634 -       
10635 +
10636         if (!username->used|| !realm->used) return -1;
10637 -       
10638 +
10639         if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
10640                 stream f;
10641                 char * f_line;
10642 -               
10643 +
10644                 if (buffer_is_empty(p->conf.auth_htdigest_userfile)) return -1;
10645 -               
10646 +
10647                 if (0 != stream_open(&f, p->conf.auth_htdigest_userfile)) {
10648                         log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", p->conf.auth_htdigest_userfile, "failed:", strerror(errno));
10649 -                       
10650 +
10651                         return -1;
10652                 }
10653 -               
10654 +
10655                 f_line = f.start;
10656 -               
10657 +
10658                 while (f_line - f.start != f.size) {
10659                         char *f_user, *f_pwd, *e, *f_realm;
10660                         size_t u_len, pwd_len, r_len;
10661 -                       
10662 +
10663                         f_user = f_line;
10664 -                       
10665 -                       /* 
10666 +
10667 +                       /*
10668                          * htdigest format
10669 -                        * 
10670 -                        * user:realm:md5(user:realm:password) 
10671 +                        *
10672 +                        * user:realm:md5(user:realm:password)
10673                          */
10674 -                       
10675 +
10676                         if (NULL == (f_realm = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
10677 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
10678 -                                               "parsed error in", p->conf.auth_htdigest_userfile, 
10679 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
10680 +                                               "parsed error in", p->conf.auth_htdigest_userfile,
10681                                                 "expected 'username:realm:hashed password'");
10682 -                               
10683 +
10684                                 stream_close(&f);
10685 -                               
10686 +
10687                                 return -1;
10688                         }
10689 -                       
10690 +
10691                         if (NULL == (f_pwd = memchr(f_realm + 1, ':', f.size - (f_realm + 1 - f.start)))) {
10692 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
10693 -                                               "parsed error in", p->conf.auth_plain_userfile, 
10694 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
10695 +                                               "parsed error in", p->conf.auth_plain_userfile,
10696                                                 "expected 'username:realm:hashed password'");
10697 -                               
10698 +
10699                                 stream_close(&f);
10700 -                               
10701 +
10702                                 return -1;
10703                         }
10704 -                       
10705 +
10706                         /* get pointers to the fields */
10707 -                       u_len = f_realm - f_user; 
10708 +                       u_len = f_realm - f_user;
10709                         f_realm++;
10710                         r_len = f_pwd - f_realm;
10711                         f_pwd++;
10712 -                       
10713 +
10714                         if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
10715                                 pwd_len = e - f_pwd;
10716                         } else {
10717                                 pwd_len = f.size - (f_pwd - f.start);
10718                         }
10719 -                       
10720 +
10721                         if (username->used - 1 == u_len &&
10722                             (realm->used - 1 == r_len) &&
10723                             (0 == strncmp(username->ptr, f_user, u_len)) &&
10724                             (0 == strncmp(realm->ptr, f_realm, r_len))) {
10725                                 /* found */
10726 -                               
10727 +
10728                                 buffer_copy_string_len(password, f_pwd, pwd_len);
10729 -                               
10730 +
10731                                 ret = 0;
10732                                 break;
10733                         }
10734 -                       
10735 +
10736                         /* EOL */
10737                         if (!e) break;
10738 -                       
10739 +
10740                         f_line = e + 1;
10741                 }
10742 -               
10743 +
10744                 stream_close(&f);
10745         } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD ||
10746                    p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
10747                 stream f;
10748                 char * f_line;
10749                 buffer *auth_fn;
10750 -               
10751 +
10752                 auth_fn = (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) ? p->conf.auth_htpasswd_userfile : p->conf.auth_plain_userfile;
10753 -               
10754 +
10755                 if (buffer_is_empty(auth_fn)) return -1;
10756 -               
10757 +
10758                 if (0 != stream_open(&f, auth_fn)) {
10759 -                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
10760 +                       log_error_write(srv, __FILE__, __LINE__, "sbss",
10761                                         "opening plain-userfile", auth_fn, "failed:", strerror(errno));
10762 -                       
10763 +
10764                         return -1;
10765                 }
10766 -               
10767 +
10768                 f_line = f.start;
10769 -               
10770 +
10771                 while (f_line - f.start != f.size) {
10772                         char *f_user, *f_pwd, *e;
10773                         size_t u_len, pwd_len;
10774 -                       
10775 +
10776                         f_user = f_line;
10777 -                       
10778 -                       /* 
10779 +
10780 +                       /*
10781                          * htpasswd format
10782 -                        * 
10783 +                        *
10784                          * user:crypted passwd
10785                          */
10786 -                       
10787 +
10788                         if (NULL == (f_pwd = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
10789 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
10790 -                                               "parsed error in", auth_fn, 
10791 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
10792 +                                               "parsed error in", auth_fn,
10793                                                 "expected 'username:hashed password'");
10794 -                               
10795 +
10796                                 stream_close(&f);
10797 -                               
10798 +
10799                                 return -1;
10800                         }
10801 -                       
10802 +
10803                         /* get pointers to the fields */
10804 -                       u_len = f_pwd - f_user; 
10805 +                       u_len = f_pwd - f_user;
10806                         f_pwd++;
10807 -                       
10808 +
10809                         if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
10810                                 pwd_len = e - f_pwd;
10811                         } else {
10812                                 pwd_len = f.size - (f_pwd - f.start);
10813                         }
10814 -                       
10815 +
10816                         if (username->used - 1 == u_len &&
10817                             (0 == strncmp(username->ptr, f_user, u_len))) {
10818                                 /* found */
10819 -                               
10820 +
10821                                 buffer_copy_string_len(password, f_pwd, pwd_len);
10822 -                               
10823 +
10824                                 ret = 0;
10825                                 break;
10826                         }
10827 -                       
10828 +
10829                         /* EOL */
10830                         if (!e) break;
10831 -                       
10832 +
10833                         f_line = e + 1;
10834                 }
10835 -               
10836 +
10837                 stream_close(&f);
10838         } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
10839                 ret = 0;
10840         } else {
10841                 return -1;
10842         }
10843 -       
10844 +
10845         return ret;
10846  }
10847  
10848 @@ -296,7 +286,7 @@
10849         int username_len;
10850         data_string *require;
10851         array *req;
10852 -       
10853 +
10854         UNUSED(group);
10855         UNUSED(host);
10856  
10857 @@ -304,12 +294,12 @@
10858         /* search auth-directives for path */
10859         for (i = 0; i < p->conf.auth_require->used; i++) {
10860                 if (p->conf.auth_require->data[i]->key->used == 0) continue;
10861 -               
10862 +
10863                 if (0 == strncmp(url, p->conf.auth_require->data[i]->key->ptr, p->conf.auth_require->data[i]->key->used - 1)) {
10864                         break;
10865                 }
10866         }
10867 -       
10868 +
10869         if (i == p->conf.auth_require->used) {
10870                 return -1;
10871         }
10872 @@ -317,72 +307,72 @@
10873         req = ((data_array *)(p->conf.auth_require->data[i]))->value;
10874  
10875         require = (data_string *)array_get_element(req, "require");
10876 -       
10877 +
10878         /* if we get here, the user we got a authed user */
10879 -       if (0 == strcmp(require->value->ptr, "valid-user")) {
10880 +       if (buffer_is_equal_string(require->value, CONST_STR_LEN("valid-user"))) {
10881                 return 0;
10882         }
10883 -       
10884 +
10885         /* user=name1|group=name3|host=name4 */
10886 -       
10887 +
10888         /* seperate the string by | */
10889  #if 0
10890         log_error_write(srv, __FILE__, __LINE__, "sb", "rules", require->value);
10891 -#endif 
10892 -       
10893 +#endif
10894 +
10895         username_len = username ? strlen(username) : 0;
10896 -       
10897 +
10898         r = rules = require->value->ptr;
10899 -       
10900 +
10901         while (1) {
10902                 const char *eq;
10903                 const char *k, *v, *e;
10904                 int k_len, v_len, r_len;
10905 -               
10906 +
10907                 e = strchr(r, '|');
10908 -               
10909 +
10910                 if (e) {
10911                         r_len = e - r;
10912                 } else {
10913                         r_len = strlen(rules) - (r - rules);
10914                 }
10915 -               
10916 +
10917                 /* from r to r + r_len is a rule */
10918 -               
10919 +
10920                 if (0 == strncmp(r, "valid-user", r_len)) {
10921 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
10922 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
10923                                         "parsing the 'require' section in 'auth.require' failed: valid-user cannot be combined with other require rules",
10924                                         require->value);
10925                         return -1;
10926                 }
10927 -               
10928 +
10929                 /* search for = in the rules */
10930                 if (NULL == (eq = strchr(r, '='))) {
10931 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
10932 -                                       "parsing the 'require' section in 'auth.require' failed: a = is missing", 
10933 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
10934 +                                       "parsing the 'require' section in 'auth.require' failed: a = is missing",
10935                                         require->value);
10936                         return -1;
10937                 }
10938 -               
10939 +
10940                 /* = out of range */
10941                 if (eq > r + r_len) {
10942 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
10943 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
10944                                         "parsing the 'require' section in 'auth.require' failed: = out of range",
10945                                         require->value);
10946 -                       
10947 +
10948                         return -1;
10949                 }
10950 -               
10951 +
10952                 /* the part before the = is user|group|host */
10953 -               
10954 +
10955                 k = r;
10956                 k_len = eq - r;
10957                 v = eq + 1;
10958                 v_len = r_len - k_len - 1;
10959 -               
10960 +
10961                 if (k_len == 4) {
10962                         if (0 == strncmp(k, "user", k_len)) {
10963 -                               if (username && 
10964 +                               if (username &&
10965                                     username_len == v_len &&
10966                                     0 == strncmp(username, v, v_len)) {
10967                                         return 0;
10968 @@ -404,19 +394,19 @@
10969                         log_error_write(srv, __FILE__, __LINE__, "s", "unknown  key");
10970                         return -1;
10971                 }
10972 -               
10973 +
10974                 if (!e) break;
10975                 r = e + 1;
10976         }
10977 -       
10978 +
10979         log_error_write(srv, __FILE__, __LINE__, "s", "nothing matched");
10980 -       
10981 +
10982         return -1;
10983  }
10984  
10985  /**
10986 - * 
10987 - * 
10988 + *
10989 + *
10990   * @param password password-string from the auth-backend
10991   * @param pw       password-string from the client
10992   */
10993 @@ -426,16 +416,16 @@
10994         UNUSED(req);
10995  
10996         if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
10997 -               /* 
10998 +               /*
10999                  * htdigest format
11000 -                * 
11001 -                * user:realm:md5(user:realm:password) 
11002 +                *
11003 +                * user:realm:md5(user:realm:password)
11004                  */
11005 -               
11006 +
11007                 MD5_CTX Md5Ctx;
11008                 HASH HA1;
11009                 char a1[256];
11010 -               
11011 +
11012                 MD5_Init(&Md5Ctx);
11013                 MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1);
11014                 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
11015 @@ -443,24 +433,24 @@
11016                 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
11017                 MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
11018                 MD5_Final(HA1, &Md5Ctx);
11019 -               
11020 +
11021                 CvtHex(HA1, a1);
11022 -               
11023 -               if (0 == strcmp(password->ptr, a1)) {
11024 +
11025 +               if (buffer_is_equal_string(password, a1, strlen(a1))) {
11026                         return 0;
11027                 }
11028 -       } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) { 
11029 -#ifdef HAVE_CRYPT      
11030 +       } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
11031 +#ifdef HAVE_CRYPT
11032                 char salt[32];
11033                 char *crypted;
11034                 size_t salt_len = 0;
11035 -               /* 
11036 +               /*
11037                  * htpasswd format
11038 -                * 
11039 +                *
11040                  * user:crypted password
11041                  */
11042  
11043 -               /* 
11044 +               /*
11045                  *  Algorithm      Salt
11046                  *  CRYPT_STD_DES   2-character (Default)
11047                  *  CRYPT_EXT_DES   9-character
11048 @@ -478,7 +468,7 @@
11049                         salt_len = 2;
11050                 } else if (password->ptr[0] == '$' && password->ptr[2] == '$') {
11051                         char *dollar = NULL;
11052 -               
11053 +
11054                         if (NULL == (dollar = strchr(password->ptr + 3, '$'))) {
11055                                 fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
11056                                 return -1;
11057 @@ -495,48 +485,21 @@
11058                 strncpy(salt, password->ptr, salt_len);
11059  
11060                 salt[salt_len] = '\0';
11061 -               
11062 +
11063                 crypted = crypt(pw, salt);
11064  
11065 -               if (0 == strcmp(password->ptr, crypted)) {
11066 +               if (buffer_is_equal_string(password, crypted, strlen(crypted))) {
11067                         return 0;
11068                 } else {
11069                         fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
11070                 }
11071 -       
11072 -#endif 
11073 -       } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) { 
11074 -               if (0 == strcmp(password->ptr, pw)) {
11075 -                       return 0;
11076 -               }
11077 -       } else if (p->conf.auth_backend == AUTH_BACKEND_PAM) { 
11078 -#ifdef USE_PAM
11079 -               pam_handle_t *pamh=NULL;
11080 -               int retval;
11081 -               
11082 -               retval = pam_start("lighttpd", username->ptr, &conv, &pamh);
11083 -               
11084 -               if (retval == PAM_SUCCESS)
11085 -                       retval = pam_authenticate(pamh, 0);    /* is user really user? */
11086 -               
11087 -               if (retval == PAM_SUCCESS)
11088 -                       retval = pam_acct_mgmt(pamh, 0);       /* permitted access? */
11089 -               
11090 -               /* This is where we have been authorized or not. */
11091 -               
11092 -               if (pam_end(pamh,retval) != PAM_SUCCESS) {     /* close Linux-PAM */
11093 -                       pamh = NULL;
11094 -                       log_error_write(srv, __FILE__, __LINE__, "s", "failed to release authenticator");
11095 -               }
11096 -               
11097 -               if (retval == PAM_SUCCESS) {
11098 -                       log_error_write(srv, __FILE__, __LINE__, "s", "Authenticated");
11099 +
11100 +#endif
11101 +       } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11102 +               if (buffer_is_equal_string(password, pw, strlen(pw))) {
11103                         return 0;
11104 -               } else {
11105 -                       log_error_write(srv, __FILE__, __LINE__, "s", "Not Authenticated");
11106                 }
11107 -#endif
11108 -       } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) { 
11109 +       } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
11110  #ifdef USE_LDAP
11111                 LDAP *ldap;
11112                 LDAPMessage *lm, *first;
11113 @@ -544,45 +507,45 @@
11114                 int ret;
11115                 char *attrs[] = { LDAP_NO_ATTRS, NULL };
11116                 size_t i;
11117 -               
11118 +
11119                 /* for now we stay synchronous */
11120 -               
11121 -               /* 
11122 +
11123 +               /*
11124                  * 1. connect anonymously (done in plugin init)
11125                  * 2. get DN for uid = username
11126                  * 3. auth against ldap server
11127                  * 4. (optional) check a field
11128                  * 5. disconnect
11129 -                * 
11130 +                *
11131                  */
11132 -               
11133 +
11134                 /* check username
11135 -                * 
11136 +                *
11137                  * we have to protect us againt username which modifies out filter in
11138                  * a unpleasant way
11139                  */
11140 -               
11141 +
11142                 for (i = 0; i < username->used - 1; i++) {
11143                         char c = username->ptr[i];
11144 -                       
11145 +
11146                         if (!isalpha(c) &&
11147                             !isdigit(c)) {
11148 -                               
11149 -                               log_error_write(srv, __FILE__, __LINE__, "sbd", 
11150 +
11151 +                               log_error_write(srv, __FILE__, __LINE__, "sbd",
11152                                         "ldap: invalid character (a-zA-Z0-9 allowed) in username:", username, i);
11153 -                               
11154 +
11155                                 return -1;
11156                         }
11157                 }
11158 -               
11159 -               
11160 -               
11161 +
11162 +
11163 +
11164                 /* build filter */
11165                 buffer_copy_string_buffer(p->ldap_filter, p->conf.ldap_filter_pre);
11166                 buffer_append_string_buffer(p->ldap_filter, username);
11167                 buffer_append_string_buffer(p->ldap_filter, p->conf.ldap_filter_post);
11168 -               
11169 -               
11170 +
11171 +
11172                 /* 2. */
11173                 if (p->conf.ldap == NULL ||
11174                     LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
11175 @@ -590,71 +553,71 @@
11176                                 return -1;
11177                         if (LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
11178  
11179 -                       log_error_write(srv, __FILE__, __LINE__, "sssb", 
11180 +                       log_error_write(srv, __FILE__, __LINE__, "sssb",
11181                                         "ldap:", ldap_err2string(ret), "filter:", p->ldap_filter);
11182 -                       
11183 +
11184                         return -1;
11185                         }
11186                 }
11187 -               
11188 +
11189                 if (NULL == (first = ldap_first_entry(p->conf.ldap, lm))) {
11190                         log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
11191 -                       
11192 +
11193                         ldap_msgfree(lm);
11194 -                       
11195 +
11196                         return -1;
11197                 }
11198 -               
11199 +
11200                 if (NULL == (dn = ldap_get_dn(p->conf.ldap, first))) {
11201                         log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
11202 -                       
11203 +
11204                         ldap_msgfree(lm);
11205 -                       
11206 +
11207                         return -1;
11208                 }
11209 -               
11210 +
11211                 ldap_msgfree(lm);
11212 -               
11213 -               
11214 +
11215 +
11216                 /* 3. */
11217                 if (NULL == (ldap = ldap_init(p->conf.auth_ldap_hostname->ptr, LDAP_PORT))) {
11218                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
11219                         return -1;
11220                 }
11221 -               
11222 +
11223                 ret = LDAP_VERSION3;
11224                 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
11225                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
11226 -                       
11227 +
11228                         ldap_unbind_s(ldap);
11229 -                       
11230 +
11231                         return -1;
11232                 }
11233 -               
11234 +
11235                 if (p->conf.auth_ldap_starttls == 1) {
11236                         if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(ldap, NULL,  NULL))) {
11237                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
11238 -               
11239 +
11240                                 ldap_unbind_s(ldap);
11241 -                               
11242 +
11243                                 return -1;
11244                         }
11245                 }
11246  
11247 -               
11248 +
11249                 if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(ldap, dn, pw))) {
11250                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
11251 -                       
11252 +
11253                         ldap_unbind_s(ldap);
11254 -                       
11255 +
11256                         return -1;
11257                 }
11258 -               
11259 +
11260                 /* 5. */
11261                 ldap_unbind_s(ldap);
11262 -               
11263 +
11264                 /* everything worked, good, access granted */
11265 -               
11266 +
11267                 return 0;
11268  #endif
11269         }
11270 @@ -664,65 +627,65 @@
11271  int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
11272         buffer *username, *password;
11273         char *pw;
11274 -       
11275 +
11276         data_string *realm;
11277 -       
11278 +
11279         realm = (data_string *)array_get_element(req, "realm");
11280 -       
11281 +
11282         username = buffer_init();
11283         password = buffer_init();
11284 -       
11285 +
11286         base64_decode(username, realm_str);
11287 -       
11288 +
11289         /* r2 == user:password */
11290         if (NULL == (pw = strchr(username->ptr, ':'))) {
11291                 buffer_free(username);
11292 -               
11293 +
11294                 log_error_write(srv, __FILE__, __LINE__, "sb", ": is missing in", username);
11295 -               
11296 +
11297                 return 0;
11298         }
11299 -       
11300 +
11301         *pw++ = '\0';
11302 -       
11303 +
11304         username->used = pw - username->ptr;
11305 -       
11306 +
11307         /* copy password to r1 */
11308         if (http_auth_get_password(srv, p, username, realm->value, password)) {
11309                 buffer_free(username);
11310                 buffer_free(password);
11311 -               
11312 +
11313                 log_error_write(srv, __FILE__, __LINE__, "s", "get_password failed");
11314 -               
11315 +
11316                 return 0;
11317         }
11318 -       
11319 +
11320         /* password doesn't match */
11321         if (http_auth_basic_password_compare(srv, p, req, username, realm->value, password, pw)) {
11322                 log_error_write(srv, __FILE__, __LINE__, "sbb", "password doesn't match for", con->uri.path, username);
11323 -               
11324 +
11325                 buffer_free(username);
11326                 buffer_free(password);
11327 -               
11328 +
11329                 return 0;
11330         }
11331 -       
11332 +
11333         /* value is our allow-rules */
11334         if (http_auth_match_rules(srv, p, url->ptr, username->ptr, NULL, NULL)) {
11335                 buffer_free(username);
11336                 buffer_free(password);
11337 -               
11338 +
11339                 log_error_write(srv, __FILE__, __LINE__, "s", "rules didn't match");
11340 -               
11341 +
11342                 return 0;
11343         }
11344 -       
11345 +
11346         /* remember the username */
11347         buffer_copy_string_buffer(p->auth_user, username);
11348 -       
11349 +
11350         buffer_free(username);
11351         buffer_free(password);
11352 -       
11353 +
11354         return 1;
11355  }
11356  
11357 @@ -735,7 +698,7 @@
11358  int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
11359         char a1[256];
11360         char a2[256];
11361 -       
11362 +
11363         char *username;
11364         char *realm;
11365         char *nonce;
11366 @@ -745,18 +708,18 @@
11367         char *cnonce;
11368         char *nc;
11369         char *respons;
11370 -       
11371 +
11372         char *e, *c;
11373         const char *m = NULL;
11374         int i;
11375         buffer *password, *b, *username_buf, *realm_buf;
11376 -       
11377 +
11378         MD5_CTX Md5Ctx;
11379         HASH HA1;
11380         HASH HA2;
11381         HASH RespHash;
11382         HASHHEX HA2Hex;
11383 -       
11384 +
11385  
11386         /* init pointers */
11387  #define S(x) \
11388 @@ -771,11 +734,11 @@
11389                 { S("cnonce=") },
11390                 { S("nc=") },
11391                 { S("response=") },
11392 -               
11393 +
11394                 { NULL, 0, NULL }
11395         };
11396  #undef S
11397 -       
11398 +
11399         dkv[0].ptr = &username;
11400         dkv[1].ptr = &realm;
11401         dkv[2].ptr = &nonce;
11402 @@ -786,24 +749,24 @@
11403         dkv[7].ptr = &nc;
11404         dkv[8].ptr = &respons;
11405         dkv[9].ptr = NULL;
11406 -       
11407 +
11408         UNUSED(req);
11409 -       
11410 +
11411         for (i = 0; dkv[i].key; i++) {
11412                 *(dkv[i].ptr) = NULL;
11413         }
11414 -       
11415 -       
11416 +
11417 +
11418         if (p->conf.auth_backend != AUTH_BACKEND_HTDIGEST &&
11419             p->conf.auth_backend != AUTH_BACKEND_PLAIN) {
11420 -               log_error_write(srv, __FILE__, __LINE__, "s", 
11421 +               log_error_write(srv, __FILE__, __LINE__, "s",
11422                                 "digest: unsupported backend (only htdigest or plain)");
11423 -               
11424 +
11425                 return -1;
11426         }
11427 -       
11428 +
11429         b = buffer_init_string(realm_str);
11430 -       
11431 +
11432         /* parse credentials from client */
11433         for (c = b->ptr; *c; c++) {
11434                 /* skip whitespaces */
11435 @@ -812,18 +775,18 @@
11436  
11437                 for (i = 0; dkv[i].key; i++) {
11438                         if ((0 == strncmp(c, dkv[i].key, dkv[i].key_len))) {
11439 -                               if ((c[dkv[i].key_len] == '"') && 
11440 +                               if ((c[dkv[i].key_len] == '"') &&
11441                                     (NULL != (e = strchr(c + dkv[i].key_len + 1, '"')))) {
11442                                         /* value with "..." */
11443                                         *(dkv[i].ptr) = c + dkv[i].key_len + 1;
11444                                         c = e;
11445 -       
11446 +
11447                                         *e = '\0';
11448                                 } else if (NULL != (e = strchr(c + dkv[i].key_len, ','))) {
11449                                         /* value without "...", terminated by ',' */
11450                                         *(dkv[i].ptr) = c + dkv[i].key_len;
11451                                         c = e;
11452 -                                       
11453 +
11454                                         *e = '\0';
11455                                 } else {
11456                                         /* value without "...", terminated by EOL */
11457 @@ -833,7 +796,7 @@
11458                         }
11459                 }
11460         }
11461 -       
11462 +
11463         if (p->conf.auth_debug > 1) {
11464                 log_error_write(srv, __FILE__, __LINE__, "ss", "username", username);
11465                 log_error_write(srv, __FILE__, __LINE__, "ss", "realm", realm);
11466 @@ -845,22 +808,22 @@
11467                 log_error_write(srv, __FILE__, __LINE__, "ss", "nc", nc);
11468                 log_error_write(srv, __FILE__, __LINE__, "ss", "response", respons);
11469         }
11470 -       
11471 +
11472         /* check if everything is transmitted */
11473 -       if (!username || 
11474 +       if (!username ||
11475             !realm ||
11476             !nonce ||
11477             !uri ||
11478             (qop && (!nc || !cnonce)) ||
11479             !respons ) {
11480                 /* missing field */
11481 -               
11482 -               log_error_write(srv, __FILE__, __LINE__, "s", 
11483 +
11484 +               log_error_write(srv, __FILE__, __LINE__, "s",
11485                                 "digest: missing field");
11486                 return -1;
11487         }
11488  
11489 -       m = get_http_method_name(con->request.http_method);     
11490 +       m = get_http_method_name(con->request.http_method);
11491  
11492         /* password-string == HA1 */
11493         password = buffer_init();
11494 @@ -873,10 +836,10 @@
11495                 buffer_free(realm_buf);
11496                 return 0;
11497         }
11498 -       
11499 +
11500         buffer_free(username_buf);
11501         buffer_free(realm_buf);
11502 -       
11503 +
11504         if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11505                 /* generate password from plain-text */
11506                 MD5_Init(&Md5Ctx);
11507 @@ -890,16 +853,16 @@
11508                 /* HA1 */
11509                 /* transform the 32-byte-hex-md5 to a 16-byte-md5 */
11510                 for (i = 0; i < HASHLEN; i++) {
11511 -                       HA1[i] = hex2int(password->ptr[i*2]) << 4; 
11512 -                       HA1[i] |= hex2int(password->ptr[i*2+1]); 
11513 +                       HA1[i] = hex2int(password->ptr[i*2]) << 4;
11514 +                       HA1[i] |= hex2int(password->ptr[i*2+1]);
11515                 }
11516         } else {
11517                 /* we already check that above */
11518                 SEGFAULT();
11519         }
11520 -       
11521 +
11522         buffer_free(password);
11523 -       
11524 +
11525         if (algorithm &&
11526             strcasecmp(algorithm, "md5-sess") == 0) {
11527                 MD5_Init(&Md5Ctx);
11528 @@ -910,9 +873,9 @@
11529                 MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
11530                 MD5_Final(HA1, &Md5Ctx);
11531         }
11532 -       
11533 +
11534         CvtHex(HA1, a1);
11535 -       
11536 +
11537         /* calculate H(A2) */
11538         MD5_Init(&Md5Ctx);
11539         MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m));
11540 @@ -924,7 +887,7 @@
11541         }
11542         MD5_Final(HA2, &Md5Ctx);
11543         CvtHex(HA2, HA2Hex);
11544 -       
11545 +
11546         /* calculate response */
11547         MD5_Init(&Md5Ctx);
11548         MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
11549 @@ -942,39 +905,39 @@
11550         MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
11551         MD5_Final(RespHash, &Md5Ctx);
11552         CvtHex(RespHash, a2);
11553 -       
11554 +
11555         if (0 != strcmp(a2, respons)) {
11556                 /* digest not ok */
11557 -               
11558 +
11559                 if (p->conf.auth_debug) {
11560 -                       log_error_write(srv, __FILE__, __LINE__, "sss", 
11561 +                       log_error_write(srv, __FILE__, __LINE__, "sss",
11562                                 "digest: digest mismatch", a2, respons);
11563                 }
11564 -               
11565 -               log_error_write(srv, __FILE__, __LINE__, "sss", 
11566 +
11567 +               log_error_write(srv, __FILE__, __LINE__, "sss",
11568                                 "digest: auth failed for", username, "wrong password");
11569 -               
11570 +
11571                 buffer_free(b);
11572                 return 0;
11573         }
11574 -       
11575 +
11576         /* value is our allow-rules */
11577         if (http_auth_match_rules(srv, p, url->ptr, username, NULL, NULL)) {
11578                 buffer_free(b);
11579 -               
11580 -               log_error_write(srv, __FILE__, __LINE__, "s", 
11581 +
11582 +               log_error_write(srv, __FILE__, __LINE__, "s",
11583                                 "digest: rules did match");
11584 -               
11585 +
11586                 return 0;
11587         }
11588 -       
11589 +
11590         /* remember the username */
11591         buffer_copy_string(p->auth_user, username);
11592 -       
11593 +
11594         buffer_free(b);
11595 -       
11596 +
11597         if (p->conf.auth_debug) {
11598 -               log_error_write(srv, __FILE__, __LINE__, "s", 
11599 +               log_error_write(srv, __FILE__, __LINE__, "s",
11600                                 "digest: auth ok");
11601         }
11602         return 1;
11603 @@ -985,23 +948,23 @@
11604         HASH h;
11605         MD5_CTX Md5Ctx;
11606         char hh[32];
11607 -       
11608 +
11609         UNUSED(p);
11610  
11611         /* generate shared-secret */
11612         MD5_Init(&Md5Ctx);
11613         MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1);
11614         MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
11615 -       
11616 +
11617         /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
11618         ltostr(hh, srv->cur_ts);
11619         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
11620         ltostr(hh, rand());
11621         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
11622 -       
11623 +
11624         MD5_Final(h, &Md5Ctx);
11625 -       
11626 +
11627         CvtHex(h, out);
11628 -       
11629 +
11630         return 0;
11631  }
11632 --- ../lighttpd-1.4.11/src/http_auth.h  2005-08-14 17:12:31.000000000 +0300
11633 +++ lighttpd-1.4.12/src/http_auth.h     2006-07-16 00:26:04.000000000 +0300
11634 @@ -9,22 +9,26 @@
11635  # include <ldap.h>
11636  #endif
11637  
11638 -typedef enum { AUTH_BACKEND_UNSET, AUTH_BACKEND_PLAIN, 
11639 -               AUTH_BACKEND_LDAP, AUTH_BACKEND_HTPASSWD, 
11640 -               AUTH_BACKEND_HTDIGEST, AUTH_BACKEND_PAM } auth_backend_t;
11641 +typedef enum {
11642 +       AUTH_BACKEND_UNSET,
11643 +       AUTH_BACKEND_PLAIN,
11644 +       AUTH_BACKEND_LDAP,
11645 +       AUTH_BACKEND_HTPASSWD,
11646 +       AUTH_BACKEND_HTDIGEST
11647 +} auth_backend_t;
11648  
11649  typedef struct {
11650         /* auth */
11651         array  *auth_require;
11652 -       
11653 +
11654         buffer *auth_plain_groupfile;
11655         buffer *auth_plain_userfile;
11656 -       
11657 +
11658         buffer *auth_htdigest_userfile;
11659         buffer *auth_htpasswd_userfile;
11660 -       
11661 +
11662         buffer *auth_backend_conf;
11663 -       
11664 +
11665         buffer *auth_ldap_hostname;
11666         buffer *auth_ldap_basedn;
11667         buffer *auth_ldap_binddn;
11668 @@ -32,15 +36,15 @@
11669         buffer *auth_ldap_filter;
11670         buffer *auth_ldap_cafile;
11671         unsigned short auth_ldap_starttls;
11672 -       
11673 +
11674         unsigned short auth_debug;
11675 -       
11676 +
11677         /* generated */
11678         auth_backend_t auth_backend;
11679 -       
11680 +
11681  #ifdef USE_LDAP
11682         LDAP *ldap;
11683 -       
11684 +
11685         buffer *ldap_filter_pre;
11686         buffer *ldap_filter_post;
11687  #endif
11688 @@ -49,15 +53,15 @@
11689  typedef struct {
11690         PLUGIN_DATA;
11691         buffer *tmp_buf;
11692 -       
11693 +
11694         buffer *auth_user;
11695  
11696  #ifdef USE_LDAP
11697         buffer *ldap_filter;
11698  #endif
11699 -       
11700 +
11701         mod_auth_plugin_config **config_storage;
11702 -       
11703 +
11704         mod_auth_plugin_config conf; /* this is only used as long as no handler_ctx is setup */
11705  } mod_auth_plugin_data;
11706  
11707 --- ../lighttpd-1.4.11/src/http_auth_digest.h   2006-01-05 00:54:01.000000000 +0200
11708 +++ lighttpd-1.4.12/src/http_auth_digest.h      2006-07-16 00:26:04.000000000 +0300
11709 @@ -12,7 +12,7 @@
11710  #ifdef USE_OPENSSL
11711  #define IN const
11712  #else
11713 -#define IN 
11714 +#define IN
11715  #endif
11716  #define OUT
11717  
11718 --- ../lighttpd-1.4.11/src/http_chunk.c 2005-08-11 01:26:50.000000000 +0300
11719 +++ lighttpd-1.4.12/src/http_chunk.c    2006-07-16 00:26:04.000000000 +0300
11720 @@ -1,7 +1,7 @@
11721  /**
11722   * the HTTP chunk-API
11723 - * 
11724 - * 
11725 + *
11726 + *
11727   */
11728  
11729  #include <sys/types.h>
11730 @@ -9,7 +9,6 @@
11731  
11732  #include <stdlib.h>
11733  #include <fcntl.h>
11734 -#include <unistd.h>
11735  
11736  #include <stdio.h>
11737  #include <errno.h>
11738 @@ -23,19 +22,19 @@
11739  static int http_chunk_append_len(server *srv, connection *con, size_t len) {
11740         size_t i, olen = len, j;
11741         buffer *b;
11742 -       
11743 +
11744         b = srv->tmp_chunk_len;
11745 -       
11746 +
11747         if (len == 0) {
11748                 buffer_copy_string(b, "0");
11749         } else {
11750                 for (i = 0; i < 8 && len; i++) {
11751                         len >>= 4;
11752                 }
11753 -               
11754 +
11755                 /* i is the number of hex digits we have */
11756                 buffer_prepare_copy(b, i + 1);
11757 -               
11758 +
11759                 for (j = i-1, len = olen; j+1 > 0; j--) {
11760                         b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
11761                         len >>= 4;
11762 @@ -43,61 +42,61 @@
11763                 b->used = i;
11764                 b->ptr[b->used++] = '\0';
11765         }
11766 -               
11767 +
11768         buffer_append_string(b, "\r\n");
11769         chunkqueue_append_buffer(con->write_queue, b);
11770 -       
11771 +
11772         return 0;
11773  }
11774  
11775  
11776  int http_chunk_append_file(server *srv, connection *con, buffer *fn, off_t offset, off_t len) {
11777         chunkqueue *cq;
11778 -       
11779 +
11780         if (!con) return -1;
11781 -       
11782 +
11783         cq = con->write_queue;
11784 -       
11785 +
11786         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11787                 http_chunk_append_len(srv, con, len);
11788         }
11789 -       
11790 +
11791         chunkqueue_append_file(cq, fn, offset, len);
11792 -       
11793 +
11794         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && len > 0) {
11795                 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11796         }
11797 -       
11798 +
11799         return 0;
11800  }
11801  
11802  int http_chunk_append_buffer(server *srv, connection *con, buffer *mem) {
11803         chunkqueue *cq;
11804 -       
11805 +
11806         if (!con) return -1;
11807 -       
11808 +
11809         cq = con->write_queue;
11810 -       
11811 +
11812         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11813                 http_chunk_append_len(srv, con, mem->used - 1);
11814         }
11815 -       
11816 +
11817         chunkqueue_append_buffer(cq, mem);
11818 -       
11819 +
11820         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && mem->used > 0) {
11821                 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11822         }
11823 -       
11824 +
11825         return 0;
11826  }
11827  
11828  int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len) {
11829         chunkqueue *cq;
11830 -       
11831 +
11832         if (!con) return -1;
11833 -       
11834 +
11835         cq = con->write_queue;
11836 -       
11837 +
11838         if (len == 0) {
11839                 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11840                         http_chunk_append_len(srv, con, 0);
11841 @@ -107,17 +106,17 @@
11842                 }
11843                 return 0;
11844         }
11845 -       
11846 +
11847         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11848                 http_chunk_append_len(srv, con, len - 1);
11849         }
11850 -       
11851 +
11852         chunkqueue_append_mem(cq, mem, len);
11853 -       
11854 +
11855         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11856                 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11857         }
11858 -       
11859 +
11860         return 0;
11861  }
11862  
11863 @@ -125,9 +124,9 @@
11864  off_t http_chunkqueue_length(server *srv, connection *con) {
11865         if (!con) {
11866                 log_error_write(srv, __FILE__, __LINE__, "s", "connection is NULL!!");
11867 -               
11868 +
11869                 return 0;
11870         }
11871 -       
11872 +
11873         return chunkqueue_length(con->write_queue);
11874  }
11875 --- ../lighttpd-1.4.11/src/http_resp.c  1970-01-01 03:00:00.000000000 +0300
11876 +++ lighttpd-1.4.12/src/http_resp.c     2006-07-18 13:03:40.000000000 +0300
11877 @@ -0,0 +1,277 @@
11878 +#include <string.h>
11879 +#include <stdlib.h>
11880 +#include <stdio.h>
11881 +#include <assert.h>
11882 +
11883 +#include "log.h"
11884 +#include "http_resp.h"
11885 +#include "http_resp_parser.h"
11886 +
11887 +/* declare prototypes for the parser */
11888 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t));
11889 +void http_resp_parserFree(void *p,  void (*freeProc)(void*));
11890 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt);
11891 +void http_resp_parser(void *, int, buffer *, http_resp_ctx_t *);
11892 +
11893 +typedef struct {
11894 +       chunkqueue *cq;
11895 +
11896 +       chunk *c; /* current chunk in the chunkqueue */
11897 +       size_t offset; /* current offset in current chunk */
11898 +
11899 +       chunk *lookup_c;
11900 +       size_t lookup_offset;
11901 +
11902 +       int is_key;
11903 +       int is_statusline;
11904 +} http_resp_tokenizer_t;
11905 +
11906 +http_resp *http_response_init(void) {
11907 +       http_resp *resp = calloc(1, sizeof(*resp));
11908 +
11909 +       resp->reason = buffer_init();
11910 +       resp->headers = array_init();
11911 +
11912 +       return resp;
11913 +}
11914 +
11915 +void http_response_reset(http_resp *resp) {
11916 +       if (!resp) return;
11917 +
11918 +       buffer_reset(resp->reason);
11919 +       array_reset(resp->headers);
11920 +
11921 +}
11922 +
11923 +void http_response_free(http_resp *resp) {
11924 +       if (!resp) return;
11925 +
11926 +       buffer_free(resp->reason);
11927 +       array_free(resp->headers);
11928 +
11929 +       free(resp);
11930 +}
11931 +
11932 +static int http_resp_get_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
11933 +       if (t->offset == t->c->mem->used - 1) {
11934 +               /* end of chunk, open next chunk */
11935 +
11936 +               if (!t->c->next) return -1;
11937 +
11938 +               t->c = t->c->next;
11939 +               t->offset = 0;
11940 +       }
11941 +
11942 +       *c = t->c->mem->ptr[t->offset++];
11943 +
11944 +       t->lookup_offset = t->offset;
11945 +       t->lookup_c = t->c;
11946 +
11947 +#if 0
11948 +       fprintf(stderr, "%s.%d: get: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->offset - 1);
11949 +#endif
11950 +
11951 +       return 0;
11952 +}
11953 +
11954 +static int http_resp_lookup_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
11955 +       if (t->lookup_offset == t->lookup_c->mem->used - 1) {
11956 +               /* end of chunk, open next chunk */
11957 +
11958 +               if (!t->lookup_c->next) return -1;
11959 +
11960 +               t->lookup_c = t->lookup_c->next;
11961 +               t->lookup_offset = 0;
11962 +       }
11963 +
11964 +       *c = t->lookup_c->mem->ptr[t->lookup_offset++];
11965 +#if 0
11966 +       fprintf(stderr, "%s.%d: lookup: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->lookup_offset - 1);
11967 +#endif
11968 +
11969 +       return 0;
11970 +}
11971 +
11972 +
11973 +static int http_resp_tokenizer(
11974 +       http_resp_tokenizer_t *t,
11975 +       int *token_id,
11976 +       buffer *token
11977 +) {
11978 +       unsigned char c;
11979 +       int tid = 0;
11980 +
11981 +       /* push the token to the parser */
11982 +
11983 +       while (tid == 0 && 0 == http_resp_get_next_char(t, &c)) {
11984 +               switch (c) {
11985 +               case ':':
11986 +                       tid = TK_COLON;
11987 +
11988 +                       t->is_key = 0;
11989 +
11990 +                       break;
11991 +               case ' ':
11992 +               case '\t':
11993 +                       /* ignore WS */
11994 +
11995 +                       break;
11996 +               case '\r':
11997 +                       if (0 != http_resp_lookup_next_char(t, &c)) return -1;
11998 +
11999 +                       if (c == '\n') {
12000 +                               tid = TK_CRLF;
12001 +
12002 +                               t->c = t->lookup_c;
12003 +                               t->offset = t->lookup_offset;
12004 +
12005 +                               t->is_statusline = 0;
12006 +                               t->is_key = 1;
12007 +                       } else {
12008 +                               fprintf(stderr, "%s.%d: CR with out LF\r\n", __FILE__, __LINE__);
12009 +                               return -1;
12010 +                       }
12011 +                       break;
12012 +               case '\n':
12013 +                       tid = TK_CRLF;
12014 +
12015 +                       t->is_statusline = 0;
12016 +                       t->is_key = 1;
12017 +
12018 +                       break;
12019 +               default:
12020 +                       while (c >= 32 && c != 127 && c != 255) {
12021 +                               if (t->is_statusline) {
12022 +                                       if (c == ':') { t->is_statusline = 0; break; } /* this is not a status line by a real header */
12023 +                                       if (c == 32) break; /* the space is a splitter in the statusline */
12024 +                               } else {
12025 +                                       if (t->is_key) {
12026 +                                               if (c == ':') break; /* the : is the splitter between key and value */
12027 +                                       }
12028 +                               }
12029 +                               if (0 != http_resp_lookup_next_char(t, &c)) return -1;
12030 +                       }
12031 +
12032 +                       if (t->c == t->lookup_c &&
12033 +                               t->offset == t->lookup_offset + 1) {
12034 +
12035 +                               fprintf(stderr, "%s.%d: invalid char in string\n", __FILE__, __LINE__);
12036 +                               return -1;
12037 +                       }
12038 +
12039 +                       tid = TK_STRING;
12040 +
12041 +                       /* the lookup points to the first invalid char */
12042 +                       t->lookup_offset--;
12043 +
12044 +                       /* no overlapping string */
12045 +                       if (t->c == t->lookup_c) {
12046 +                               buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->lookup_offset - t->offset + 1);
12047 +                       } else {
12048 +                               /* first chunk */
12049 +                               buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->c->mem->used - t->offset);
12050 +
12051 +                               /* chunks in the middle */
12052 +                               for (t->c = t->c->next; t->c != t->lookup_c; t->c = t->c->next) {
12053 +                                       buffer_append_string_buffer(token, t->c->mem);
12054 +                                       t->offset = t->c->mem->used - 1;
12055 +                               }
12056 +
12057 +                               /* last chunk */
12058 +                               buffer_append_string_len(token, t->c->mem->ptr, t->lookup_offset);
12059 +                       }
12060 +
12061 +                       t->offset = t->lookup_offset;
12062 +
12063 +                       break;
12064 +               }
12065 +       }
12066 +
12067 +       if (tid) {
12068 +               *token_id = tid;
12069 +
12070 +               return 1;
12071 +       }
12072 +
12073 +       return -1;
12074 +}
12075 +
12076 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *resp) {
12077 +       http_resp_tokenizer_t t;
12078 +       void *pParser = NULL;
12079 +       int token_id = 0;
12080 +       buffer *token = NULL;
12081 +       http_resp_ctx_t context;
12082 +       parse_status_t ret = PARSE_UNSET;
12083 +       int last_token_id = 0;
12084 +
12085 +       t.cq = cq;
12086 +       t.c = cq->first;
12087 +       t.offset = t.c->offset;
12088 +       t.is_key = 0;
12089 +       t.is_statusline = 1;
12090 +
12091 +       context.ok = 1;
12092 +       context.errmsg = buffer_init();
12093 +       context.resp = resp;
12094 +
12095 +       pParser = http_resp_parserAlloc( malloc );
12096 +       token = buffer_init();
12097 +#if 0
12098 +       http_resp_parserTrace(stderr, "http-response: "); 
12099 +#endif
12100 +
12101 +       while((1 == http_resp_tokenizer(&t, &token_id, token)) && context.ok) {
12102 +               http_resp_parser(pParser, token_id, token, &context);
12103 +
12104 +               token = buffer_init();
12105 +
12106 +               /* CRLF CRLF ... the header end sequence */
12107 +               if (last_token_id == TK_CRLF &&
12108 +                   token_id == TK_CRLF) break;
12109 +
12110 +               last_token_id = token_id;
12111 +       }
12112 +
12113 +       /* oops, the parser failed */
12114 +       if (context.ok == 0) {
12115 +               ret = PARSE_ERROR;
12116 +
12117 +               if (!buffer_is_empty(context.errmsg)) {
12118 +                       TRACE("parsing failed: %s", BUF_STR(context.errmsg));
12119 +               } else {
12120 +                       TRACE("%s", "parsing failed ...");
12121 +               }
12122 +       }
12123 +
12124 +       http_resp_parser(pParser, 0, token, &context);
12125 +       http_resp_parserFree(pParser, free);
12126 +
12127 +       if (context.ok == 0) {
12128 +               /* we are missing the some tokens */
12129 +
12130 +               if (!buffer_is_empty(context.errmsg)) {
12131 +                       TRACE("parsing failed: %s", BUF_STR(context.errmsg));
12132 +               }
12133 +
12134 +               if (ret == PARSE_UNSET) {
12135 +                       ret = buffer_is_empty(context.errmsg) ? PARSE_NEED_MORE : PARSE_ERROR;
12136 +               }
12137 +       } else {
12138 +               chunk *c;
12139 +
12140 +               for (c = cq->first; c != t.c; c = c->next) {
12141 +                       c->offset = c->mem->used - 1;
12142 +               }
12143 +
12144 +               c->offset = t.offset;
12145 +
12146 +               ret = PARSE_SUCCESS;
12147 +       }
12148 +
12149 +       buffer_free(token);
12150 +       buffer_free(context.errmsg);
12151 +
12152 +       return ret;
12153 +}
12154 +
12155 --- ../lighttpd-1.4.11/src/http_resp.h  1970-01-01 03:00:00.000000000 +0300
12156 +++ lighttpd-1.4.12/src/http_resp.h     2006-07-16 00:26:04.000000000 +0300
12157 @@ -0,0 +1,34 @@
12158 +#ifndef _HTTP_RESP_H_
12159 +#define _HTTP_RESP_H_
12160 +
12161 +#include "array.h"
12162 +#include "chunk.h"
12163 +
12164 +typedef enum {
12165 +    PARSE_UNSET,
12166 +    PARSE_SUCCESS,
12167 +    PARSE_ERROR,
12168 +    PARSE_NEED_MORE
12169 +} parse_status_t;
12170 +
12171 +typedef struct {
12172 +    int protocol;   /* http/1.0, http/1.1 */
12173 +    int status;     /* e.g. 200 */
12174 +    buffer *reason; /* e.g. Ok */
12175 +    array *headers;
12176 +} http_resp;
12177 +
12178 +typedef struct {
12179 +       int     ok;
12180 +    buffer *errmsg;
12181 +
12182 +    http_resp *resp;
12183 +} http_resp_ctx_t;
12184 +
12185 +http_resp *http_response_init(void);
12186 +void http_response_free(http_resp *resp);
12187 +void http_response_reset(http_resp *resp);
12188 +
12189 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *http_response);
12190 +
12191 +#endif
12192 --- ../lighttpd-1.4.11/src/http_resp_parser.c   1970-01-01 03:00:00.000000000 +0300
12193 +++ lighttpd-1.4.12/src/http_resp_parser.c      2006-07-18 13:03:52.000000000 +0300
12194 @@ -0,0 +1,901 @@
12195 +/* Driver template for the LEMON parser generator.
12196 +** The author disclaims copyright to this source code.
12197 +*/
12198 +/* First off, code is include which follows the "include" declaration
12199 +** in the input file. */
12200 +#include <stdio.h>
12201 +#line 6 "./http_resp_parser.y"
12202 +
12203 +#include <assert.h>
12204 +#include <string.h>
12205 +#include "http_resp.h"
12206 +#include "keyvalue.h"
12207 +#include "array.h"
12208 +#include "log.h"
12209 +
12210 +#line 17 "http_resp_parser.c"
12211 +/* Next is all token values, in a form suitable for use by makeheaders.
12212 +** This section will be null unless lemon is run with the -m switch.
12213 +*/
12214 +/*
12215 +** These constants (all generated automatically by the parser generator)
12216 +** specify the various kinds of tokens (terminals) that the parser
12217 +** understands.
12218 +**
12219 +** Each symbol here is a terminal symbol in the grammar.
12220 +*/
12221 +/* Make sure the INTERFACE macro is defined.
12222 +*/
12223 +#ifndef INTERFACE
12224 +# define INTERFACE 1
12225 +#endif
12226 +/* The next thing included is series of defines which control
12227 +** various aspects of the generated parser.
12228 +**    YYCODETYPE         is the data type used for storing terminal
12229 +**                       and nonterminal numbers.  "unsigned char" is
12230 +**                       used if there are fewer than 250 terminals
12231 +**                       and nonterminals.  "int" is used otherwise.
12232 +**    YYNOCODE           is a number of type YYCODETYPE which corresponds
12233 +**                       to no legal terminal or nonterminal number.  This
12234 +**                       number is used to fill in empty slots of the hash
12235 +**                       table.
12236 +**    YYFALLBACK         If defined, this indicates that one or more tokens
12237 +**                       have fall-back values which should be used if the
12238 +**                       original value of the token will not parse.
12239 +**    YYACTIONTYPE       is the data type used for storing terminal
12240 +**                       and nonterminal numbers.  "unsigned char" is
12241 +**                       used if there are fewer than 250 rules and
12242 +**                       states combined.  "int" is used otherwise.
12243 +**    http_resp_parserTOKENTYPE     is the data type used for minor tokens given
12244 +**                       directly to the parser from the tokenizer.
12245 +**    YYMINORTYPE        is the data type used for all minor tokens.
12246 +**                       This is typically a union of many types, one of
12247 +**                       which is http_resp_parserTOKENTYPE.  The entry in the union
12248 +**                       for base tokens is called "yy0".
12249 +**    YYSTACKDEPTH       is the maximum depth of the parser's stack.
12250 +**    http_resp_parserARG_SDECL     A static variable declaration for the %extra_argument
12251 +**    http_resp_parserARG_PDECL     A parameter declaration for the %extra_argument
12252 +**    http_resp_parserARG_STORE     Code to store %extra_argument into yypParser
12253 +**    http_resp_parserARG_FETCH     Code to extract %extra_argument from yypParser
12254 +**    YYNSTATE           the combined number of states.
12255 +**    YYNRULE            the number of rules in the grammar
12256 +**    YYERRORSYMBOL      is the code number of the error symbol.  If not
12257 +**                       defined, then do no error processing.
12258 +*/
12259 +/* \ 1 */
12260 +#define YYCODETYPE unsigned char
12261 +#define YYNOCODE 12
12262 +#define YYACTIONTYPE unsigned char
12263 +#define http_resp_parserTOKENTYPE buffer *
12264 +typedef union {
12265 +  http_resp_parserTOKENTYPE yy0;
12266 +  http_resp * yy2;
12267 +  data_string * yy9;
12268 +  array * yy12;
12269 +  int yy20;
12270 +  int yy23;
12271 +} YYMINORTYPE;
12272 +#define YYSTACKDEPTH 100
12273 +#define http_resp_parserARG_SDECL http_resp_ctx_t *ctx;
12274 +#define http_resp_parserARG_PDECL ,http_resp_ctx_t *ctx
12275 +#define http_resp_parserARG_FETCH http_resp_ctx_t *ctx = yypParser->ctx
12276 +#define http_resp_parserARG_STORE yypParser->ctx = ctx
12277 +#define YYNSTATE 19
12278 +#define YYNRULE 9
12279 +#define YYERRORSYMBOL 4
12280 +#define YYERRSYMDT yy23
12281 +#define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
12282 +#define YY_ACCEPT_ACTION  (YYNSTATE+YYNRULE+1)
12283 +#define YY_ERROR_ACTION   (YYNSTATE+YYNRULE)
12284 +
12285 +/* Next are that tables used to determine what action to take based on the
12286 +** current state and lookahead token.  These tables are used to implement
12287 +** functions that take a state number and lookahead value and return an
12288 +** action integer.
12289 +**
12290 +** Suppose the action integer is N.  Then the action is determined as
12291 +** follows
12292 +**
12293 +**   0 <= N < YYNSTATE                  Shift N.  That is, push the lookahead
12294 +**                                      token onto the stack and goto state N.
12295 +**
12296 +**   YYNSTATE <= N < YYNSTATE+YYNRULE   Reduce by rule N-YYNSTATE.
12297 +**
12298 +**   N == YYNSTATE+YYNRULE              A syntax error has occurred.
12299 +**
12300 +**   N == YYNSTATE+YYNRULE+1            The parser accepts its input.
12301 +**
12302 +**   N == YYNSTATE+YYNRULE+2            No such action.  Denotes unused
12303 +**                                      slots in the yy_action[] table.
12304 +**
12305 +** The action table is constructed as a single large table named yy_action[].
12306 +** Given state S and lookahead X, the action is computed as
12307 +**
12308 +**      yy_action[ yy_shift_ofst[S] + X ]
12309 +**
12310 +** If the index value yy_shift_ofst[S]+X is out of range or if the value
12311 +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
12312 +** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
12313 +** and that yy_default[S] should be used instead.
12314 +**
12315 +** The formula above is for computing the action when the lookahead is
12316 +** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
12317 +** a reduce action) then the yy_reduce_ofst[] array is used in place of
12318 +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
12319 +** YY_SHIFT_USE_DFLT.
12320 +**
12321 +** The following are the tables generated in this section:
12322 +**
12323 +**  yy_action[]        A single table containing all actions.
12324 +**  yy_lookahead[]     A table containing the lookahead for each entry in
12325 +**                     yy_action.  Used to detect hash collisions.
12326 +**  yy_shift_ofst[]    For each state, the offset into yy_action for
12327 +**                     shifting terminals.
12328 +**  yy_reduce_ofst[]   For each state, the offset into yy_action for
12329 +**                     shifting non-terminals after a reduce.
12330 +**  yy_default[]       Default action for each state.
12331 +*/
12332 +static YYACTIONTYPE yy_action[] = {
12333 + /*     0 */     8,   29,   18,    1,   14,    2,    4,   11,   15,   12,
12334 + /*    10 */    14,   13,    4,   21,    5,   19,    3,    5,    6,    7,
12335 + /*    20 */     9,   17,   16,    4,   20,   22,   22,   10,
12336 +};
12337 +static YYCODETYPE yy_lookahead[] = {
12338 + /*     0 */     5,    6,    2,    8,    9,    1,    2,    1,    2,    8,
12339 + /*    10 */     9,    1,    2,    2,    3,    0,    9,    3,    2,    1,
12340 + /*    20 */     7,    2,    2,    2,    0,    2,   11,   10,
12341 +};
12342 +#define YY_SHIFT_USE_DFLT (-1)
12343 +static signed char yy_shift_ofst[] = {
12344 + /*     0 */     0,    4,   15,   -1,   14,   16,   18,   -1,   19,   20,
12345 + /*    10 */     6,   21,   10,   24,   -1,   -1,   -1,   23,   11,
12346 +};
12347 +#define YY_REDUCE_USE_DFLT (-6)
12348 +static signed char yy_reduce_ofst[] = {
12349 + /*     0 */    -5,    7,   -6,   -6,   -6,   -6,   -6,   -6,   13,   17,
12350 + /*    10 */    -6,    1,    7,   -6,   -6,   -6,   -6,   -6,   -6,
12351 +};
12352 +static YYACTIONTYPE yy_default[] = {
12353 + /*     0 */    28,   28,   28,   25,   28,   28,   28,   27,   28,   28,
12354 + /*    10 */    28,   28,   28,   28,   26,   24,   23,   28,   28,
12355 +};
12356 +#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
12357 +
12358 +/* The next table maps tokens into fallback tokens.  If a construct
12359 +** like the following:
12360 +**
12361 +**      %fallback ID X Y Z.
12362 +**
12363 +** appears in the grammer, then ID becomes a fallback token for X, Y,
12364 +** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
12365 +** but it does not parse, the type of the token is changed to ID and
12366 +** the parse is retried before an error is thrown.
12367 +*/
12368 +#ifdef YYFALLBACK
12369 +static const YYCODETYPE yyFallback[] = {
12370 +};
12371 +#endif /* YYFALLBACK */
12372 +
12373 +/* The following structure represents a single element of the
12374 +** parser's stack.  Information stored includes:
12375 +**
12376 +**   +  The state number for the parser at this level of the stack.
12377 +**
12378 +**   +  The value of the token stored at this level of the stack.
12379 +**      (In other words, the "major" token.)
12380 +**
12381 +**   +  The semantic value stored at this level of the stack.  This is
12382 +**      the information used by the action routines in the grammar.
12383 +**      It is sometimes called the "minor" token.
12384 +*/
12385 +struct yyStackEntry {
12386 +  int stateno;       /* The state-number */
12387 +  int major;         /* The major token value.  This is the code
12388 +                     ** number for the token at this stack level */
12389 +  YYMINORTYPE minor; /* The user-supplied minor token value.  This
12390 +                     ** is the value of the token  */
12391 +};
12392 +typedef struct yyStackEntry yyStackEntry;
12393 +
12394 +/* The state of the parser is completely contained in an instance of
12395 +** the following structure */
12396 +struct yyParser {
12397 +  int yyidx;                    /* Index of top element in stack */
12398 +  int yyerrcnt;                 /* Shifts left before out of the error */
12399 +  http_resp_parserARG_SDECL                /* A place to hold %extra_argument */
12400 +  yyStackEntry yystack[YYSTACKDEPTH];  /* The parser's stack */
12401 +};
12402 +typedef struct yyParser yyParser;
12403 +
12404 +#ifndef NDEBUG
12405 +#include <stdio.h>
12406 +static FILE *yyTraceFILE = 0;
12407 +static char *yyTracePrompt = 0;
12408 +#endif /* NDEBUG */
12409 +
12410 +#ifndef NDEBUG
12411 +/*
12412 +** Turn parser tracing on by giving a stream to which to write the trace
12413 +** and a prompt to preface each trace message.  Tracing is turned off
12414 +** by making either argument NULL
12415 +**
12416 +** Inputs:
12417 +** <ul>
12418 +** <li> A FILE* to which trace output should be written.
12419 +**      If NULL, then tracing is turned off.
12420 +** <li> A prefix string written at the beginning of every
12421 +**      line of trace output.  If NULL, then tracing is
12422 +**      turned off.
12423 +** </ul>
12424 +**
12425 +** Outputs:
12426 +** None.
12427 +*/
12428 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt){
12429 +  yyTraceFILE = TraceFILE;
12430 +  yyTracePrompt = zTracePrompt;
12431 +  if( yyTraceFILE==0 ) yyTracePrompt = 0;
12432 +  else if( yyTracePrompt==0 ) yyTraceFILE = 0;
12433 +}
12434 +#endif /* NDEBUG */
12435 +
12436 +#ifndef NDEBUG
12437 +/* For tracing shifts, the names of all terminals and nonterminals
12438 +** are required.  The following table supplies these names */
12439 +static const char *yyTokenName[] = {
12440 +  "$",             "CRLF",          "STRING",        "COLON",       
12441 +  "error",         "protocol",      "response_hdr",  "number",      
12442 +  "headers",       "header",        "reason",      
12443 +};
12444 +#endif /* NDEBUG */
12445 +
12446 +#ifndef NDEBUG
12447 +/* For tracing reduce actions, the names of all rules are required.
12448 +*/
12449 +static const char *yyRuleName[] = {
12450 + /*   0 */ "response_hdr ::= headers CRLF",
12451 + /*   1 */ "response_hdr ::= protocol number reason CRLF headers CRLF",
12452 + /*   2 */ "protocol ::= STRING",
12453 + /*   3 */ "number ::= STRING",
12454 + /*   4 */ "reason ::= STRING",
12455 + /*   5 */ "reason ::= reason STRING",
12456 + /*   6 */ "headers ::= headers header",
12457 + /*   7 */ "headers ::= header",
12458 + /*   8 */ "header ::= STRING COLON STRING CRLF",
12459 +};
12460 +#endif /* NDEBUG */
12461 +
12462 +/*
12463 +** This function returns the symbolic name associated with a token
12464 +** value.
12465 +*/
12466 +const char *http_resp_parserTokenName(int tokenType){
12467 +#ifndef NDEBUG
12468 +  if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
12469 +    return yyTokenName[tokenType];
12470 +  }else{
12471 +    return "Unknown";
12472 +  }
12473 +#else
12474 +  return "";
12475 +#endif
12476 +}
12477 +
12478 +/*
12479 +** This function allocates a new parser.
12480 +** The only argument is a pointer to a function which works like
12481 +** malloc.
12482 +**
12483 +** Inputs:
12484 +** A pointer to the function used to allocate memory.
12485 +**
12486 +** Outputs:
12487 +** A pointer to a parser.  This pointer is used in subsequent calls
12488 +** to http_resp_parser and http_resp_parserFree.
12489 +*/
12490 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t)){
12491 +  yyParser *pParser;
12492 +  pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
12493 +  if( pParser ){
12494 +    pParser->yyidx = -1;
12495 +  }
12496 +  return pParser;
12497 +}
12498 +
12499 +/* The following function deletes the value associated with a
12500 +** symbol.  The symbol can be either a terminal or nonterminal.
12501 +** "yymajor" is the symbol code, and "yypminor" is a pointer to
12502 +** the value.
12503 +*/
12504 +static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
12505 +  switch( yymajor ){
12506 +    /* Here is inserted the actions which take place when a
12507 +    ** terminal or non-terminal is destroyed.  This can happen
12508 +    ** when the symbol is popped from the stack during a
12509 +    ** reduce or during error processing or when a parser is
12510 +    ** being destroyed before it is finished parsing.
12511 +    **
12512 +    ** Note: during a reduce, the only symbols destroyed are those
12513 +    ** which appear on the RHS of the rule, but which are not used
12514 +    ** inside the C code.
12515 +    */
12516 +    case 1:
12517 +    case 2:
12518 +    case 3:
12519 +#line 25 "./http_resp_parser.y"
12520 +{ buffer_free((yypminor->yy0)); }
12521 +#line 327 "http_resp_parser.c"
12522 +      break;
12523 +    case 10:
12524 +#line 24 "./http_resp_parser.y"
12525 +{ buffer_free((yypminor->yy0)); }
12526 +#line 332 "http_resp_parser.c"
12527 +      break;
12528 +    default:  break;   /* If no destructor action specified: do nothing */
12529 +  }
12530 +}
12531 +
12532 +/*
12533 +** Pop the parser's stack once.
12534 +**
12535 +** If there is a destructor routine associated with the token which
12536 +** is popped from the stack, then call it.
12537 +**
12538 +** Return the major token number for the symbol popped.
12539 +*/
12540 +static int yy_pop_parser_stack(yyParser *pParser){
12541 +  YYCODETYPE yymajor;
12542 +  yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
12543 +
12544 +  if( pParser->yyidx<0 ) return 0;
12545 +#ifndef NDEBUG
12546 +  if( yyTraceFILE && pParser->yyidx>=0 ){
12547 +    fprintf(yyTraceFILE,"%sPopping %s\n",
12548 +      yyTracePrompt,
12549 +      yyTokenName[yytos->major]);
12550 +  }
12551 +#endif
12552 +  yymajor = yytos->major;
12553 +  yy_destructor( yymajor, &yytos->minor);
12554 +  pParser->yyidx--;
12555 +  return yymajor;
12556 +}
12557 +
12558 +/*
12559 +** Deallocate and destroy a parser.  Destructors are all called for
12560 +** all stack elements before shutting the parser down.
12561 +**
12562 +** Inputs:
12563 +** <ul>
12564 +** <li>  A pointer to the parser.  This should be a pointer
12565 +**       obtained from http_resp_parserAlloc.
12566 +** <li>  A pointer to a function used to reclaim memory obtained
12567 +**       from malloc.
12568 +** </ul>
12569 +*/
12570 +void http_resp_parserFree(
12571 +  void *p,                    /* The parser to be deleted */
12572 +  void (*freeProc)(void*)     /* Function used to reclaim memory */
12573 +){
12574 +  yyParser *pParser = (yyParser*)p;
12575 +  if( pParser==0 ) return;
12576 +  while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
12577 +  (*freeProc)((void*)pParser);
12578 +}
12579 +
12580 +/*
12581 +** Find the appropriate action for a parser given the terminal
12582 +** look-ahead token iLookAhead.
12583 +**
12584 +** If the look-ahead token is YYNOCODE, then check to see if the action is
12585 +** independent of the look-ahead.  If it is, return the action, otherwise
12586 +** return YY_NO_ACTION.
12587 +*/
12588 +static int yy_find_shift_action(
12589 +  yyParser *pParser,        /* The parser */
12590 +  int iLookAhead            /* The look-ahead token */
12591 +){
12592 +  int i;
12593 +  int stateno = pParser->yystack[pParser->yyidx].stateno;
12594 +
12595 +  /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
12596 +  i = yy_shift_ofst[stateno];
12597 +  if( i==YY_SHIFT_USE_DFLT ){
12598 +    return yy_default[stateno];
12599 +  }
12600 +  if( iLookAhead==YYNOCODE ){
12601 +    return YY_NO_ACTION;
12602 +  }
12603 +  i += iLookAhead;
12604 +  if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
12605 +#ifdef YYFALLBACK
12606 +    int iFallback;            /* Fallback token */
12607 +    if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
12608 +           && (iFallback = yyFallback[iLookAhead])!=0 ){
12609 +#ifndef NDEBUG
12610 +      if( yyTraceFILE ){
12611 +        fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
12612 +           yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
12613 +      }
12614 +#endif
12615 +      return yy_find_shift_action(pParser, iFallback);
12616 +    }
12617 +#endif
12618 +    return yy_default[stateno];
12619 +  }else{
12620 +    return yy_action[i];
12621 +  }
12622 +}
12623 +
12624 +/*
12625 +** Find the appropriate action for a parser given the non-terminal
12626 +** look-ahead token iLookAhead.
12627 +**
12628 +** If the look-ahead token is YYNOCODE, then check to see if the action is
12629 +** independent of the look-ahead.  If it is, return the action, otherwise
12630 +** return YY_NO_ACTION.
12631 +*/
12632 +static int yy_find_reduce_action(
12633 +  yyParser *pParser,        /* The parser */
12634 +  int iLookAhead            /* The look-ahead token */
12635 +){
12636 +  int i;
12637 +  int stateno = pParser->yystack[pParser->yyidx].stateno;
12638 +
12639 +  i = yy_reduce_ofst[stateno];
12640 +  if( i==YY_REDUCE_USE_DFLT ){
12641 +    return yy_default[stateno];
12642 +  }
12643 +  if( iLookAhead==YYNOCODE ){
12644 +    return YY_NO_ACTION;
12645 +  }
12646 +  i += iLookAhead;
12647 +  if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
12648 +    return yy_default[stateno];
12649 +  }else{
12650 +    return yy_action[i];
12651 +  }
12652 +}
12653 +
12654 +/*
12655 +** Perform a shift action.
12656 +*/
12657 +static void yy_shift(
12658 +  yyParser *yypParser,          /* The parser to be shifted */
12659 +  int yyNewState,               /* The new state to shift in */
12660 +  int yyMajor,                  /* The major token to shift in */
12661 +  YYMINORTYPE *yypMinor         /* Pointer ot the minor token to shift in */
12662 +){
12663 +  yyStackEntry *yytos;
12664 +  yypParser->yyidx++;
12665 +  if( yypParser->yyidx>=YYSTACKDEPTH ){
12666 +     http_resp_parserARG_FETCH;
12667 +     yypParser->yyidx--;
12668 +#ifndef NDEBUG
12669 +     if( yyTraceFILE ){
12670 +       fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
12671 +     }
12672 +#endif
12673 +     while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12674 +     /* Here code is inserted which will execute if the parser
12675 +     ** stack every overflows */
12676 +     http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument var */
12677 +     return;
12678 +  }
12679 +  yytos = &yypParser->yystack[yypParser->yyidx];
12680 +  yytos->stateno = yyNewState;
12681 +  yytos->major = yyMajor;
12682 +  yytos->minor = *yypMinor;
12683 +#ifndef NDEBUG
12684 +  if( yyTraceFILE && yypParser->yyidx>0 ){
12685 +    int i;
12686 +    fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
12687 +    fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
12688 +    for(i=1; i<=yypParser->yyidx; i++)
12689 +      fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
12690 +    fprintf(yyTraceFILE,"\n");
12691 +  }
12692 +#endif
12693 +}
12694 +
12695 +/* The following table contains information about every rule that
12696 +** is used during the reduce.
12697 +*/
12698 +static struct {
12699 +  YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
12700 +  unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
12701 +} yyRuleInfo[] = {
12702 +  { 6, 2 },
12703 +  { 6, 6 },
12704 +  { 5, 1 },
12705 +  { 7, 1 },
12706 +  { 10, 1 },
12707 +  { 10, 2 },
12708 +  { 8, 2 },
12709 +  { 8, 1 },
12710 +  { 9, 4 },
12711 +};
12712 +
12713 +static void yy_accept(yyParser*);  /* Forward Declaration */
12714 +
12715 +/*
12716 +** Perform a reduce action and the shift that must immediately
12717 +** follow the reduce.
12718 +*/
12719 +static void yy_reduce(
12720 +  yyParser *yypParser,         /* The parser */
12721 +  int yyruleno                 /* Number of the rule by which to reduce */
12722 +){
12723 +  int yygoto;                     /* The next state */
12724 +  int yyact;                      /* The next action */
12725 +  YYMINORTYPE yygotominor;        /* The LHS of the rule reduced */
12726 +  yyStackEntry *yymsp;            /* The top of the parser's stack */
12727 +  int yysize;                     /* Amount to pop the stack */
12728 +  http_resp_parserARG_FETCH;
12729 +  yymsp = &yypParser->yystack[yypParser->yyidx];
12730 +#ifndef NDEBUG
12731 +  if( yyTraceFILE && yyruleno>=0
12732 +        && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
12733 +    fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
12734 +      yyRuleName[yyruleno]);
12735 +  }
12736 +#endif /* NDEBUG */
12737 +
12738 +  switch( yyruleno ){
12739 +  /* Beginning here are the reduction cases.  A typical example
12740 +  ** follows:
12741 +  **   case 0:
12742 +  **  #line <lineno> <grammarfile>
12743 +  **     { ... }           // User supplied code
12744 +  **  #line <lineno> <thisfile>
12745 +  **     break;
12746 +  */
12747 +      case 0:
12748 +#line 28 "./http_resp_parser.y"
12749 +{
12750 +    http_resp *resp = ctx->resp;
12751 +    data_string *ds;
12752
12753 +    resp->protocol = HTTP_VERSION_UNSET;
12754 +
12755 +    buffer_copy_string(resp->reason, ""); /* no reason */
12756 +    array_free(resp->headers);
12757 +    resp->headers = yymsp[-1].minor.yy12;
12758 +
12759 +    if (NULL == (ds = (data_string *)array_get_element(yymsp[-1].minor.yy12, "Status"))) { 
12760 +        resp->status = 0;
12761 +    } else {
12762 +        char *err;
12763 +        resp->status = strtol(ds->value->ptr, &err, 10);
12764 +   
12765 +        if (*err != '\0' && *err != ' ') {
12766 +            buffer_copy_string(ctx->errmsg, "expected a number: ");
12767 +            buffer_append_string_buffer(ctx->errmsg, ds->value);
12768 +            buffer_append_string(ctx->errmsg, err);
12769 +        
12770 +            ctx->ok = 0;
12771 +        }
12772 +    }
12773 +
12774 +    yymsp[-1].minor.yy12 = NULL;
12775 +}
12776 +#line 582 "http_resp_parser.c"
12777 +  yy_destructor(1,&yymsp[0].minor);
12778 +        break;
12779 +      case 1:
12780 +#line 56 "./http_resp_parser.y"
12781 +{
12782 +    http_resp *resp = ctx->resp;
12783 +    
12784 +    resp->status = yymsp[-4].minor.yy20;
12785 +    resp->protocol = yymsp[-5].minor.yy20;
12786 +    buffer_copy_string_buffer(resp->reason, yymsp[-3].minor.yy0);
12787 +    buffer_free(yymsp[-3].minor.yy0); 
12788 +
12789 +    array_free(resp->headers);
12790 +    
12791 +    resp->headers = yymsp[-1].minor.yy12;
12792 +}
12793 +#line 599 "http_resp_parser.c"
12794 +  yy_destructor(1,&yymsp[-2].minor);
12795 +  yy_destructor(1,&yymsp[0].minor);
12796 +        break;
12797 +      case 2:
12798 +#line 69 "./http_resp_parser.y"
12799 +{
12800 +    if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.0"))) {
12801 +        yygotominor.yy20 = HTTP_VERSION_1_0;
12802 +    } else if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.1"))) {
12803 +        yygotominor.yy20 = HTTP_VERSION_1_1;
12804 +    } else {
12805 +        buffer_copy_string(ctx->errmsg, "unknown protocol: ");
12806 +        buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
12807 +        
12808 +        ctx->ok = 0;
12809 +    }
12810 +    buffer_free(yymsp[0].minor.yy0);
12811 +}
12812 +#line 618 "http_resp_parser.c"
12813 +        break;
12814 +      case 3:
12815 +#line 83 "./http_resp_parser.y"
12816 +{
12817 +    char *err;
12818 +    yygotominor.yy20 = strtol(yymsp[0].minor.yy0->ptr, &err, 10);
12819 +    
12820 +    if (*err != '\0') {
12821 +        buffer_copy_string(ctx->errmsg, "expected a number, got: ");
12822 +        buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
12823 +        
12824 +        ctx->ok = 0;
12825 +    }
12826 +    buffer_free(yymsp[0].minor.yy0);
12827 +}
12828 +#line 634 "http_resp_parser.c"
12829 +        break;
12830 +      case 4:
12831 +#line 96 "./http_resp_parser.y"
12832 +{
12833 +    yygotominor.yy0 = yymsp[0].minor.yy0;
12834 +}
12835 +#line 641 "http_resp_parser.c"
12836 +        break;
12837 +      case 5:
12838 +#line 100 "./http_resp_parser.y"
12839 +{
12840 +    yygotominor.yy0 = yymsp[-1].minor.yy0;
12841 +    
12842 +    buffer_append_string(yygotominor.yy0, " ");
12843 +    buffer_append_string_buffer(yygotominor.yy0, yymsp[0].minor.yy0);
12844 +
12845 +    buffer_free(yymsp[0].minor.yy0); 
12846 +}
12847 +#line 653 "http_resp_parser.c"
12848 +        break;
12849 +      case 6:
12850 +#line 109 "./http_resp_parser.y"
12851 +{
12852 +    yygotominor.yy12 = yymsp[-1].minor.yy12;
12853 +    
12854 +    array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
12855 +}
12856 +#line 662 "http_resp_parser.c"
12857 +        break;
12858 +      case 7:
12859 +#line 115 "./http_resp_parser.y"
12860 +{
12861 +    yygotominor.yy12 = array_init();
12862 +
12863 +    array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
12864 +}
12865 +#line 671 "http_resp_parser.c"
12866 +        break;
12867 +      case 8:
12868 +#line 120 "./http_resp_parser.y"
12869 +{
12870 +    yygotominor.yy9 = data_string_init();
12871 +    
12872 +    buffer_copy_string_buffer(yygotominor.yy9->key, yymsp[-3].minor.yy0);
12873 +    buffer_copy_string_buffer(yygotominor.yy9->value, yymsp[-1].minor.yy0);    
12874 +    buffer_free(yymsp[-3].minor.yy0);
12875 +    buffer_free(yymsp[-1].minor.yy0);
12876 +}
12877 +#line 683 "http_resp_parser.c"
12878 +  yy_destructor(3,&yymsp[-2].minor);
12879 +  yy_destructor(1,&yymsp[0].minor);
12880 +        break;
12881 +  };
12882 +  yygoto = yyRuleInfo[yyruleno].lhs;
12883 +  yysize = yyRuleInfo[yyruleno].nrhs;
12884 +  yypParser->yyidx -= yysize;
12885 +  yyact = yy_find_reduce_action(yypParser,yygoto);
12886 +  if( yyact < YYNSTATE ){
12887 +    yy_shift(yypParser,yyact,yygoto,&yygotominor);
12888 +  }else if( yyact == YYNSTATE + YYNRULE + 1 ){
12889 +    yy_accept(yypParser);
12890 +  }
12891 +}
12892 +
12893 +/*
12894 +** The following code executes when the parse fails
12895 +*/
12896 +static void yy_parse_failed(
12897 +  yyParser *yypParser           /* The parser */
12898 +){
12899 +  http_resp_parserARG_FETCH;
12900 +#ifndef NDEBUG
12901 +  if( yyTraceFILE ){
12902 +    fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
12903 +  }
12904 +#endif
12905 +  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12906 +  /* Here code is inserted which will be executed whenever the
12907 +  ** parser fails */
12908 +#line 15 "./http_resp_parser.y"
12909 +
12910 +  ctx->ok = 0;
12911 +
12912 +#line 718 "http_resp_parser.c"
12913 +  http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12914 +}
12915 +
12916 +/*
12917 +** The following code executes when a syntax error first occurs.
12918 +*/
12919 +static void yy_syntax_error(
12920 +  yyParser *yypParser,           /* The parser */
12921 +  int yymajor,                   /* The major type of the error token */
12922 +  YYMINORTYPE yyminor            /* The minor type of the error token */
12923 +){
12924 +  http_resp_parserARG_FETCH;
12925 +#define TOKEN (yyminor.yy0)
12926 +  http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12927 +}
12928 +
12929 +/*
12930 +** The following is executed when the parser accepts
12931 +*/
12932 +static void yy_accept(
12933 +  yyParser *yypParser           /* The parser */
12934 +){
12935 +  http_resp_parserARG_FETCH;
12936 +#ifndef NDEBUG
12937 +  if( yyTraceFILE ){
12938 +    fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
12939 +  }
12940 +#endif
12941 +  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12942 +  /* Here code is inserted which will be executed whenever the
12943 +  ** parser accepts */
12944 +  http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12945 +}
12946 +
12947 +/* The main parser program.
12948 +** The first argument is a pointer to a structure obtained from
12949 +** "http_resp_parserAlloc" which describes the current state of the parser.
12950 +** The second argument is the major token number.  The third is
12951 +** the minor token.  The fourth optional argument is whatever the
12952 +** user wants (and specified in the grammar) and is available for
12953 +** use by the action routines.
12954 +**
12955 +** Inputs:
12956 +** <ul>
12957 +** <li> A pointer to the parser (an opaque structure.)
12958 +** <li> The major token number.
12959 +** <li> The minor token number.
12960 +** <li> An option argument of a grammar-specified type.
12961 +** </ul>
12962 +**
12963 +** Outputs:
12964 +** None.
12965 +*/
12966 +void http_resp_parser(
12967 +  void *yyp,                   /* The parser */
12968 +  int yymajor,                 /* The major token code number */
12969 +  http_resp_parserTOKENTYPE yyminor       /* The value for the token */
12970 +  http_resp_parserARG_PDECL               /* Optional %extra_argument parameter */
12971 +){
12972 +  YYMINORTYPE yyminorunion;
12973 +  int yyact;            /* The parser action. */
12974 +  int yyendofinput;     /* True if we are at the end of input */
12975 +  int yyerrorhit = 0;   /* True if yymajor has invoked an error */
12976 +  yyParser *yypParser;  /* The parser */
12977 +
12978 +  /* (re)initialize the parser, if necessary */
12979 +  yypParser = (yyParser*)yyp;
12980 +  if( yypParser->yyidx<0 ){
12981 +    if( yymajor==0 ) return;
12982 +    yypParser->yyidx = 0;
12983 +    yypParser->yyerrcnt = -1;
12984 +    yypParser->yystack[0].stateno = 0;
12985 +    yypParser->yystack[0].major = 0;
12986 +  }
12987 +  yyminorunion.yy0 = yyminor;
12988 +  yyendofinput = (yymajor==0);
12989 +  http_resp_parserARG_STORE;
12990 +
12991 +#ifndef NDEBUG
12992 +  if( yyTraceFILE ){
12993 +    fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
12994 +  }
12995 +#endif
12996 +
12997 +  do{
12998 +    yyact = yy_find_shift_action(yypParser,yymajor);
12999 +    if( yyact<YYNSTATE ){
13000 +      yy_shift(yypParser,yyact,yymajor,&yyminorunion);
13001 +      yypParser->yyerrcnt--;
13002 +      if( yyendofinput && yypParser->yyidx>=0 ){
13003 +        yymajor = 0;
13004 +      }else{
13005 +        yymajor = YYNOCODE;
13006 +      }
13007 +    }else if( yyact < YYNSTATE + YYNRULE ){
13008 +      yy_reduce(yypParser,yyact-YYNSTATE);
13009 +    }else if( yyact == YY_ERROR_ACTION ){
13010 +      int yymx;
13011 +#ifndef NDEBUG
13012 +      if( yyTraceFILE ){
13013 +        fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
13014 +      }
13015 +#endif
13016 +#ifdef YYERRORSYMBOL
13017 +      /* A syntax error has occurred.
13018 +      ** The response to an error depends upon whether or not the
13019 +      ** grammar defines an error token "ERROR".
13020 +      **
13021 +      ** This is what we do if the grammar does define ERROR:
13022 +      **
13023 +      **  * Call the %syntax_error function.
13024 +      **
13025 +      **  * Begin popping the stack until we enter a state where
13026 +      **    it is legal to shift the error symbol, then shift
13027 +      **    the error symbol.
13028 +      **
13029 +      **  * Set the error count to three.
13030 +      **
13031 +      **  * Begin accepting and shifting new tokens.  No new error
13032 +      **    processing will occur until three tokens have been
13033 +      **    shifted successfully.
13034 +      **
13035 +      */
13036 +      if( yypParser->yyerrcnt<0 ){
13037 +        yy_syntax_error(yypParser,yymajor,yyminorunion);
13038 +      }
13039 +      yymx = yypParser->yystack[yypParser->yyidx].major;
13040 +      if( yymx==YYERRORSYMBOL || yyerrorhit ){
13041 +#ifndef NDEBUG
13042 +        if( yyTraceFILE ){
13043 +          fprintf(yyTraceFILE,"%sDiscard input token %s\n",
13044 +             yyTracePrompt,yyTokenName[yymajor]);
13045 +        }
13046 +#endif
13047 +        yy_destructor(yymajor,&yyminorunion);
13048 +        yymajor = YYNOCODE;
13049 +      }else{
13050 +         while(
13051 +          yypParser->yyidx >= 0 &&
13052 +          yymx != YYERRORSYMBOL &&
13053 +          (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
13054 +        ){
13055 +          yy_pop_parser_stack(yypParser);
13056 +        }
13057 +        if( yypParser->yyidx < 0 || yymajor==0 ){
13058 +          yy_destructor(yymajor,&yyminorunion);
13059 +          yy_parse_failed(yypParser);
13060 +          yymajor = YYNOCODE;
13061 +        }else if( yymx!=YYERRORSYMBOL ){
13062 +          YYMINORTYPE u2;
13063 +          u2.YYERRSYMDT = 0;
13064 +          yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
13065 +        }
13066 +      }
13067 +      yypParser->yyerrcnt = 3;
13068 +      yyerrorhit = 1;
13069 +#else  /* YYERRORSYMBOL is not defined */
13070 +      /* This is what we do if the grammar does not define ERROR:
13071 +      **
13072 +      **  * Report an error message, and throw away the input token.
13073 +      **
13074 +      **  * If the input token is $, then fail the parse.
13075 +      **
13076 +      ** As before, subsequent error messages are suppressed until
13077 +      ** three input tokens have been successfully shifted.
13078 +      */
13079 +      if( yypParser->yyerrcnt<=0 ){
13080 +        yy_syntax_error(yypParser,yymajor,yyminorunion);
13081 +      }
13082 +      yypParser->yyerrcnt = 3;
13083 +      yy_destructor(yymajor,&yyminorunion);
13084 +      if( yyendofinput ){
13085 +        yy_parse_failed(yypParser);
13086 +      }
13087 +      yymajor = YYNOCODE;
13088 +#endif
13089 +    }else{
13090 +      yy_accept(yypParser);
13091 +      yymajor = YYNOCODE;
13092 +    }
13093 +  }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
13094 +  return;
13095 +}
13096 --- ../lighttpd-1.4.11/src/http_resp_parser.h   1970-01-01 03:00:00.000000000 +0300
13097 +++ lighttpd-1.4.12/src/http_resp_parser.h      2006-07-18 13:03:52.000000000 +0300
13098 @@ -0,0 +1,3 @@
13099 +#define TK_CRLF                            1
13100 +#define TK_STRING                          2
13101 +#define TK_COLON                           3
13102 --- ../lighttpd-1.4.11/src/http_resp_parser.y   1970-01-01 03:00:00.000000000 +0300
13103 +++ lighttpd-1.4.12/src/http_resp_parser.y      2006-07-18 13:03:40.000000000 +0300
13104 @@ -0,0 +1,127 @@
13105 +%token_prefix TK_
13106 +%token_type {buffer *}
13107 +%extra_argument {http_resp_ctx_t *ctx}
13108 +%name http_resp_parser
13109 +
13110 +%include {
13111 +#include <assert.h>
13112 +#include <string.h>
13113 +#include "http_resp.h"
13114 +#include "keyvalue.h"
13115 +#include "array.h"
13116 +#include "log.h"
13117 +}
13118 +
13119 +%parse_failure {
13120 +  ctx->ok = 0;
13121 +}
13122 +
13123 +%type protocol { int }
13124 +%type response_hdr { http_resp * }
13125 +%type number { int }
13126 +%type headers { array * }
13127 +%type header { data_string * }
13128 +%destructor reason { buffer_free($$); }
13129 +%token_destructor { buffer_free($$); }
13130 +
13131 +/* just headers + Status: ... */
13132 +response_hdr ::= headers(HDR) CRLF . {
13133 +    http_resp *resp = ctx->resp;
13134 +    data_string *ds;
13135
13136 +    resp->protocol = HTTP_VERSION_UNSET;
13137 +
13138 +    buffer_copy_string(resp->reason, ""); /* no reason */
13139 +    array_free(resp->headers);
13140 +    resp->headers = HDR;
13141 +
13142 +    if (NULL == (ds = (data_string *)array_get_element(HDR, "Status"))) { 
13143 +        resp->status = 0;
13144 +    } else {
13145 +        char *err;
13146 +        resp->status = strtol(ds->value->ptr, &err, 10);
13147 +   
13148 +        if (*err != '\0' && *err != ' ') {
13149 +            buffer_copy_string(ctx->errmsg, "expected a number: ");
13150 +            buffer_append_string_buffer(ctx->errmsg, ds->value);
13151 +            buffer_append_string(ctx->errmsg, err);
13152 +        
13153 +            ctx->ok = 0;
13154 +        }
13155 +    }
13156 +
13157 +    HDR = NULL;
13158 +}
13159 +/* HTTP/1.0 <status> ... */
13160 +response_hdr ::= protocol(B) number(C) reason(D) CRLF headers(HDR) CRLF . {
13161 +    http_resp *resp = ctx->resp;
13162 +    
13163 +    resp->status = C;
13164 +    resp->protocol = B;
13165 +    buffer_copy_string_buffer(resp->reason, D);
13166 +    buffer_free(D); 
13167 +
13168 +    array_free(resp->headers);
13169 +    
13170 +    resp->headers = HDR;
13171 +}
13172 +
13173 +protocol(A) ::= STRING(B). {
13174 +    if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.0"))) {
13175 +        A = HTTP_VERSION_1_0;
13176 +    } else if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.1"))) {
13177 +        A = HTTP_VERSION_1_1;
13178 +    } else {
13179 +        buffer_copy_string(ctx->errmsg, "unknown protocol: ");
13180 +        buffer_append_string_buffer(ctx->errmsg, B);
13181 +        
13182 +        ctx->ok = 0;
13183 +    }
13184 +    buffer_free(B);
13185 +}
13186 +
13187 +number(A) ::= STRING(B). {
13188 +    char *err;
13189 +    A = strtol(B->ptr, &err, 10);
13190 +    
13191 +    if (*err != '\0') {
13192 +        buffer_copy_string(ctx->errmsg, "expected a number, got: ");
13193 +        buffer_append_string_buffer(ctx->errmsg, B);
13194 +        
13195 +        ctx->ok = 0;
13196 +    }
13197 +    buffer_free(B);
13198 +}
13199 +
13200 +reason(A) ::= STRING(B). {
13201 +    A = B;
13202 +}
13203 +
13204 +reason(A) ::= reason(C) STRING(B). {
13205 +    A = C;
13206 +    
13207 +    buffer_append_string(A, " ");
13208 +    buffer_append_string_buffer(A, B);
13209 +
13210 +    buffer_free(B); 
13211 +}
13212 +
13213 +headers(HDRS) ::= headers(SRC) header(HDR). {
13214 +    HDRS = SRC;
13215 +    
13216 +    array_insert_unique(HDRS, (data_unset *)HDR);
13217 +}
13218 +
13219 +headers(HDRS) ::= header(HDR). {
13220 +    HDRS = array_init();
13221 +
13222 +    array_insert_unique(HDRS, (data_unset *)HDR);
13223 +}
13224 +header(HDR) ::= STRING(A) COLON STRING(B) CRLF. {
13225 +    HDR = data_string_init();
13226 +    
13227 +    buffer_copy_string_buffer(HDR->key, A);
13228 +    buffer_copy_string_buffer(HDR->value, B);    
13229 +    buffer_free(A);
13230 +    buffer_free(B);
13231 +}
13232 --- ../lighttpd-1.4.11/src/inet_ntop_cache.c    2005-08-11 01:26:38.000000000 +0300
13233 +++ lighttpd-1.4.12/src/inet_ntop_cache.c       2006-07-16 00:26:04.000000000 +0300
13234 @@ -8,7 +8,7 @@
13235  #include "sys-socket.h"
13236  
13237  const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) {
13238 -#ifdef HAVE_IPV6       
13239 +#ifdef HAVE_IPV6
13240         size_t ndx = 0, i;
13241         for (i = 0; i < INET_NTOP_CACHE_MAX; i++) {
13242                 if (srv->inet_ntop_cache[i].ts != 0) {
13243 @@ -20,31 +20,31 @@
13244                                    srv->inet_ntop_cache[i].addr.ipv4.s_addr == addr->ipv4.sin_addr.s_addr) {
13245                                 /* IPv4 found in cache */
13246                                 break;
13247 -                               
13248 +
13249                         }
13250                 }
13251         }
13252 -       
13253 +
13254         if (i == INET_NTOP_CACHE_MAX) {
13255                 /* not found in cache */
13256 -               
13257 +
13258                 i = ndx;
13259 -               inet_ntop(addr->plain.sa_family, 
13260 -                         addr->plain.sa_family == AF_INET6 ? 
13261 +               inet_ntop(addr->plain.sa_family,
13262 +                         addr->plain.sa_family == AF_INET6 ?
13263                           (const void *) &(addr->ipv6.sin6_addr) :
13264                           (const void *) &(addr->ipv4.sin_addr),
13265                           srv->inet_ntop_cache[i].b2, INET6_ADDRSTRLEN);
13266 -               
13267 +
13268                 srv->inet_ntop_cache[i].ts = srv->cur_ts;
13269                 srv->inet_ntop_cache[i].family = addr->plain.sa_family;
13270 -               
13271 +
13272                 if (srv->inet_ntop_cache[i].family == AF_INET) {
13273                         srv->inet_ntop_cache[i].addr.ipv4.s_addr = addr->ipv4.sin_addr.s_addr;
13274                 } else if (srv->inet_ntop_cache[i].family == AF_INET6) {
13275                         memcpy(srv->inet_ntop_cache[i].addr.ipv6.s6_addr, addr->ipv6.sin6_addr.s6_addr, 16);
13276                 }
13277         }
13278 -       
13279 +
13280         return srv->inet_ntop_cache[i].b2;
13281  #else
13282         UNUSED(srv);
13283 --- ../lighttpd-1.4.11/src/iosocket.c   1970-01-01 03:00:00.000000000 +0300
13284 +++ lighttpd-1.4.12/src/iosocket.c      2006-07-18 13:03:40.000000000 +0300
13285 @@ -0,0 +1,36 @@
13286 +#include <stdlib.h>
13287 +
13288 +#include "iosocket.h"
13289 +#include "sys-socket.h"
13290 +#include "sys-files.h"
13291 +#include "array-static.h"
13292 +
13293 +iosocket *iosocket_init(void) {
13294 +       STRUCT_INIT(iosocket, sock);
13295 +
13296 +       sock->fde_ndx = -1;
13297 +       sock->fd = -1;
13298 +
13299 +       sock->type = IOSOCKET_TYPE_SOCKET;
13300 +
13301 +       return sock;
13302 +}
13303 +
13304 +void iosocket_free(iosocket *sock) {
13305 +       if (!sock) return;
13306 +
13307 +       if (sock->fd != -1) {
13308 +               switch (sock->type) {
13309 +               case IOSOCKET_TYPE_SOCKET:
13310 +                       closesocket(sock->fd);
13311 +                       break;
13312 +               case IOSOCKET_TYPE_PIPE:
13313 +                       close(sock->fd);
13314 +                       break;
13315 +               default:
13316 +                       break;
13317 +               }
13318 +       }
13319 +
13320 +       free(sock);
13321 +}
13322 --- ../lighttpd-1.4.11/src/iosocket.h   1970-01-01 03:00:00.000000000 +0300
13323 +++ lighttpd-1.4.12/src/iosocket.h      2006-07-18 13:03:40.000000000 +0300
13324 @@ -0,0 +1,32 @@
13325 +#ifndef _IOSOCKET_H_
13326 +#define _IOSOCKET_H_
13327 +
13328 +#if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
13329 +# define USE_OPENSSL
13330 +# include <openssl/ssl.h>
13331 +#endif
13332 +
13333 +typedef enum {
13334 +       IOSOCKET_TYPE_UNSET,
13335 +       IOSOCKET_TYPE_SOCKET,
13336 +       IOSOCKET_TYPE_PIPE
13337 +} iosocket_t;
13338 +
13339 +/**
13340 + * a non-blocking fd
13341 + */
13342 +typedef struct {
13343 +       int fd;
13344 +       int fde_ndx;
13345 +
13346 +#ifdef USE_OPENSSL
13347 +       SSL *ssl;
13348 +#endif
13349 +
13350 +       iosocket_t type; /**< sendfile on solaris doesn't work on pipes */
13351 +} iosocket;
13352 +
13353 +iosocket *iosocket_init(void);
13354 +void iosocket_free(iosocket *sock);
13355 +
13356 +#endif
13357 --- ../lighttpd-1.4.11/src/joblist.c    2005-08-11 01:26:41.000000000 +0300
13358 +++ lighttpd-1.4.12/src/joblist.c       2006-07-16 00:26:03.000000000 +0300
13359 @@ -7,7 +7,7 @@
13360  
13361  int joblist_append(server *srv, connection *con) {
13362         if (con->in_joblist) return 0;
13363 -       
13364 +
13365         if (srv->joblist->size == 0) {
13366                 srv->joblist->size  = 16;
13367                 srv->joblist->ptr   = malloc(sizeof(*srv->joblist->ptr) * srv->joblist->size);
13368 @@ -15,15 +15,15 @@
13369                 srv->joblist->size += 16;
13370                 srv->joblist->ptr   = realloc(srv->joblist->ptr, sizeof(*srv->joblist->ptr) * srv->joblist->size);
13371         }
13372 -       
13373 +
13374         srv->joblist->ptr[srv->joblist->used++] = con;
13375 -       
13376 +
13377         return 0;
13378  }
13379  
13380  void joblist_free(server *srv, connections *joblist) {
13381         UNUSED(srv);
13382 -               
13383 +
13384         free(joblist->ptr);
13385         free(joblist);
13386  }
13387 @@ -31,14 +31,14 @@
13388  connection *fdwaitqueue_unshift(server *srv, connections *fdwaitqueue) {
13389         connection *con;
13390         UNUSED(srv);
13391 -               
13392 -       
13393 +
13394 +
13395         if (fdwaitqueue->used == 0) return NULL;
13396 -       
13397 +
13398         con = fdwaitqueue->ptr[0];
13399 -       
13400 +
13401         memmove(fdwaitqueue->ptr, &(fdwaitqueue->ptr[1]), --fdwaitqueue->used * sizeof(*(fdwaitqueue->ptr)));
13402 -       
13403 +
13404         return con;
13405  }
13406  
13407 @@ -50,9 +50,9 @@
13408                 srv->fdwaitqueue->size += 16;
13409                 srv->fdwaitqueue->ptr   = realloc(srv->fdwaitqueue->ptr, sizeof(*(srv->fdwaitqueue->ptr)) * srv->fdwaitqueue->size);
13410         }
13411 -       
13412 +
13413         srv->fdwaitqueue->ptr[srv->fdwaitqueue->used++] = con;
13414 -       
13415 +
13416         return 0;
13417  }
13418  
13419 --- ../lighttpd-1.4.11/src/keyvalue.c   2006-03-02 16:08:06.000000000 +0200
13420 +++ lighttpd-1.4.12/src/keyvalue.c      2006-07-16 00:26:03.000000000 +0300
13421 @@ -87,7 +87,8 @@
13422         { 504, "Gateway Timeout" },
13423         { 505, "HTTP Version Not Supported" },
13424         { 507, "Insufficient Storage" }, /* WebDAV */
13425 -       
13426 +       { 509, "Bandwidth Limit exceeded" },
13427 +
13428         { -1, NULL }
13429  };
13430  
13431 @@ -102,12 +103,12 @@
13432         { 501, "501.html" },
13433         { 503, "503.html" },
13434         { 505, "505.html" },
13435 -       
13436 +
13437         { -1, NULL }
13438  };
13439  
13440  
13441 -const char *keyvalue_get_value(keyvalue *kv, int k) { 
13442 +const char *keyvalue_get_value(keyvalue *kv, int k) {
13443         int i;
13444         for (i = 0; kv[i].value; i++) {
13445                 if (kv[i].key == k) return kv[i].value;
13446 @@ -115,7 +116,7 @@
13447         return NULL;
13448  }
13449  
13450 -int keyvalue_get_key(keyvalue *kv, const char *s) { 
13451 +int keyvalue_get_key(keyvalue *kv, const char *s) {
13452         int i;
13453         for (i = 0; kv[i].value; i++) {
13454                 if (0 == strcmp(kv[i].value, s)) return kv[i].key;
13455 @@ -125,9 +126,9 @@
13456  
13457  keyvalue_buffer *keyvalue_buffer_init(void) {
13458         keyvalue_buffer *kvb;
13459 -       
13460 +
13461         kvb = calloc(1, sizeof(*kvb));
13462 -       
13463 +
13464         return kvb;
13465  }
13466  
13467 @@ -135,49 +136,49 @@
13468         size_t i;
13469         if (kvb->size == 0) {
13470                 kvb->size = 4;
13471 -               
13472 +
13473                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13474 -               
13475 +
13476                 for(i = 0; i < kvb->size; i++) {
13477                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13478                 }
13479         } else if (kvb->used == kvb->size) {
13480                 kvb->size += 4;
13481 -               
13482 +
13483                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13484 -               
13485 +
13486                 for(i = kvb->used; i < kvb->size; i++) {
13487                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13488                 }
13489         }
13490 -       
13491 +
13492         kvb->kv[kvb->used]->key = key;
13493         kvb->kv[kvb->used]->value = strdup(value);
13494 -       
13495 +
13496         kvb->used++;
13497 -       
13498 +
13499         return 0;
13500  }
13501  
13502  void keyvalue_buffer_free(keyvalue_buffer *kvb) {
13503         size_t i;
13504 -       
13505 +
13506         for (i = 0; i < kvb->size; i++) {
13507                 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
13508                 free(kvb->kv[i]);
13509         }
13510 -       
13511 +
13512         if (kvb->kv) free(kvb->kv);
13513 -       
13514 +
13515         free(kvb);
13516  }
13517  
13518  
13519  s_keyvalue_buffer *s_keyvalue_buffer_init(void) {
13520         s_keyvalue_buffer *kvb;
13521 -       
13522 +
13523         kvb = calloc(1, sizeof(*kvb));
13524 -       
13525 +
13526         return kvb;
13527  }
13528  
13529 @@ -186,50 +187,50 @@
13530         if (kvb->size == 0) {
13531                 kvb->size = 4;
13532                 kvb->used = 0;
13533 -               
13534 +
13535                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13536 -               
13537 +
13538                 for(i = 0; i < kvb->size; i++) {
13539                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13540                 }
13541         } else if (kvb->used == kvb->size) {
13542                 kvb->size += 4;
13543 -               
13544 +
13545                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13546 -               
13547 +
13548                 for(i = kvb->used; i < kvb->size; i++) {
13549                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13550                 }
13551         }
13552 -       
13553 +
13554         kvb->kv[kvb->used]->key = key ? strdup(key) : NULL;
13555         kvb->kv[kvb->used]->value = strdup(value);
13556 -       
13557 +
13558         kvb->used++;
13559 -       
13560 +
13561         return 0;
13562  }
13563  
13564  void s_keyvalue_buffer_free(s_keyvalue_buffer *kvb) {
13565         size_t i;
13566 -       
13567 +
13568         for (i = 0; i < kvb->size; i++) {
13569                 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
13570                 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
13571                 free(kvb->kv[i]);
13572         }
13573 -       
13574 +
13575         if (kvb->kv) free(kvb->kv);
13576 -       
13577 +
13578         free(kvb);
13579  }
13580  
13581  
13582  httpauth_keyvalue_buffer *httpauth_keyvalue_buffer_init(void) {
13583         httpauth_keyvalue_buffer *kvb;
13584 -       
13585 +
13586         kvb = calloc(1, sizeof(*kvb));
13587 -       
13588 +
13589         return kvb;
13590  }
13591  
13592 @@ -237,42 +238,42 @@
13593         size_t i;
13594         if (kvb->size == 0) {
13595                 kvb->size = 4;
13596 -               
13597 +
13598                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13599 -               
13600 +
13601                 for(i = 0; i < kvb->size; i++) {
13602                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13603                 }
13604         } else if (kvb->used == kvb->size) {
13605                 kvb->size += 4;
13606 -               
13607 +
13608                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13609 -               
13610 +
13611                 for(i = kvb->used; i < kvb->size; i++) {
13612                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13613                 }
13614         }
13615 -       
13616 +
13617         kvb->kv[kvb->used]->key = strdup(key);
13618         kvb->kv[kvb->used]->realm = strdup(realm);
13619         kvb->kv[kvb->used]->type = type;
13620 -       
13621 +
13622         kvb->used++;
13623 -       
13624 +
13625         return 0;
13626  }
13627  
13628  void httpauth_keyvalue_buffer_free(httpauth_keyvalue_buffer *kvb) {
13629         size_t i;
13630 -       
13631 +
13632         for (i = 0; i < kvb->size; i++) {
13633                 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
13634                 if (kvb->kv[i]->realm) free(kvb->kv[i]->realm);
13635                 free(kvb->kv[i]);
13636         }
13637 -       
13638 +
13639         if (kvb->kv) free(kvb->kv);
13640 -       
13641 +
13642         free(kvb);
13643  }
13644  
13645 @@ -306,9 +307,9 @@
13646  
13647  pcre_keyvalue_buffer *pcre_keyvalue_buffer_init(void) {
13648         pcre_keyvalue_buffer *kvb;
13649 -       
13650 +
13651         kvb = calloc(1, sizeof(*kvb));
13652 -       
13653 +
13654         return kvb;
13655  }
13656  
13657 @@ -319,46 +320,46 @@
13658         int erroff;
13659         pcre_keyvalue *kv;
13660  #endif
13661 -       
13662 +
13663         if (!key) return -1;
13664  
13665  #ifdef HAVE_PCRE_H
13666         if (kvb->size == 0) {
13667                 kvb->size = 4;
13668                 kvb->used = 0;
13669 -               
13670 +
13671                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13672 -               
13673 +
13674                 for(i = 0; i < kvb->size; i++) {
13675                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13676                 }
13677         } else if (kvb->used == kvb->size) {
13678                 kvb->size += 4;
13679 -               
13680 +
13681                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13682 -               
13683 +
13684                 for(i = kvb->used; i < kvb->size; i++) {
13685                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13686                 }
13687         }
13688 -       
13689 +
13690         kv = kvb->kv[kvb->used];
13691         if (NULL == (kv->key = pcre_compile(key,
13692                                           0, &errptr, &erroff, NULL))) {
13693 -               
13694 +
13695                 fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr);
13696                 return -1;
13697         }
13698  
13699 -       if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&  
13700 +       if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
13701                         errptr != NULL) {
13702                 return -1;
13703         }
13704 -       
13705 +
13706         kv->value = buffer_init_string(value);
13707 -       
13708 +
13709         kvb->used++;
13710 -       
13711 +
13712         return 0;
13713  #else
13714         UNUSED(kvb);
13715 @@ -380,9 +381,9 @@
13716                 if (kv->value) buffer_free(kv->value);
13717                 free(kv);
13718         }
13719 -       
13720 +
13721         if (kvb->kv) free(kvb->kv);
13722  #endif
13723 -       
13724 +
13725         free(kvb);
13726  }
13727 --- ../lighttpd-1.4.11/src/keyvalue.h   2006-03-02 16:08:06.000000000 +0200
13728 +++ lighttpd-1.4.12/src/keyvalue.h      2006-07-16 00:26:04.000000000 +0300
13729 @@ -9,19 +9,19 @@
13730  # include <pcre.h>
13731  #endif
13732  
13733 -typedef enum { 
13734 -       HTTP_METHOD_UNSET = -1, 
13735 -       HTTP_METHOD_GET, 
13736 -       HTTP_METHOD_POST, 
13737 -       HTTP_METHOD_HEAD, 
13738 -       HTTP_METHOD_OPTIONS, 
13739 +typedef enum {
13740 +       HTTP_METHOD_UNSET = -1,
13741 +       HTTP_METHOD_GET,
13742 +       HTTP_METHOD_POST,
13743 +       HTTP_METHOD_HEAD,
13744 +       HTTP_METHOD_OPTIONS,
13745         HTTP_METHOD_PROPFIND,  /* WebDAV */
13746 -       HTTP_METHOD_MKCOL, 
13747 -       HTTP_METHOD_PUT, 
13748 -       HTTP_METHOD_DELETE, 
13749 -       HTTP_METHOD_COPY, 
13750 -       HTTP_METHOD_MOVE, 
13751 -       HTTP_METHOD_PROPPATCH, 
13752 +       HTTP_METHOD_MKCOL,
13753 +       HTTP_METHOD_PUT,
13754 +       HTTP_METHOD_DELETE,
13755 +       HTTP_METHOD_COPY,
13756 +       HTTP_METHOD_MOVE,
13757 +       HTTP_METHOD_PROPPATCH,
13758         HTTP_METHOD_REPORT, /* DeltaV */
13759         HTTP_METHOD_CHECKOUT,
13760         HTTP_METHOD_CHECKIN,
13761 @@ -39,13 +39,13 @@
13762  
13763  typedef struct {
13764         int key;
13765 -       
13766 +
13767         char *value;
13768  } keyvalue;
13769  
13770  typedef struct {
13771         char *key;
13772 -       
13773 +
13774         char *value;
13775  } s_keyvalue;
13776  
13777 @@ -54,7 +54,7 @@
13778         pcre *key;
13779         pcre_extra *key_extra;
13780  #endif
13781 -       
13782 +
13783         buffer *value;
13784  } pcre_keyvalue;
13785  
13786 @@ -62,7 +62,7 @@
13787  
13788  typedef struct {
13789         char *key;
13790 -       
13791 +
13792         char *realm;
13793         httpauth_type type;
13794  } httpauth_keyvalue;
13795 --- ../lighttpd-1.4.11/src/lemon.c      2005-09-01 00:21:34.000000000 +0300
13796 +++ lighttpd-1.4.12/src/lemon.c 2006-07-16 00:26:03.000000000 +0300
13797 @@ -579,7 +579,7 @@
13798  */
13799  
13800  /* Find a precedence symbol of every rule in the grammar.
13801 -** 
13802 +**
13803  ** Those rules which have a precedence symbol coded in the input
13804  ** grammar using the "[symbol]" construct will already have the
13805  ** rp->precsym field filled.  Other rules take as their precedence
13806 @@ -869,7 +869,7 @@
13807        cfp->status = INCOMPLETE;
13808      }
13809    }
13810 -  
13811 +
13812    do{
13813      progress = 0;
13814      for(i=0; i<lemp->nstate; i++){
13815 @@ -900,7 +900,7 @@
13816    struct symbol *sp;
13817    struct rule *rp;
13818  
13819 -  /* Add all of the reduce actions 
13820 +  /* Add all of the reduce actions
13821    ** A reduce action is added for each element of the followset of
13822    ** a configuration which has its dot at the extreme right.
13823    */
13824 @@ -1017,7 +1017,7 @@
13825        apx->type = RD_RESOLVED;
13826      }
13827    }else{
13828 -    assert( 
13829 +    assert(
13830        apx->type==SH_RESOLVED ||
13831        apx->type==RD_RESOLVED ||
13832        apx->type==CONFLICT ||
13833 @@ -1350,7 +1350,7 @@
13834    OptInit(argv,options,stderr);
13835    if( version ){
13836       printf("Lemon version 1.0\n");
13837 -     exit(0); 
13838 +     exit(0);
13839    }
13840    if( OptNArgs() < 1 ){
13841      fprintf(stderr,"Exactly one filename argument is required.\n");
13842 @@ -2031,7 +2031,7 @@
13843      case IN_RHS:
13844        if( x[0]=='.' ){
13845          struct rule *rp;
13846 -        rp = (struct rule *)malloc( sizeof(struct rule) + 
13847 +        rp = (struct rule *)malloc( sizeof(struct rule) +
13848               sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs );
13849          if( rp==0 ){
13850            ErrorMsg(psp->filename,psp->tokenlineno,
13851 @@ -2546,7 +2546,7 @@
13852    return fp;
13853  }
13854  
13855 -/* Duplicate the input file without comments and without actions 
13856 +/* Duplicate the input file without comments and without actions
13857  ** on rules */
13858  void Reprint(lemp)
13859  struct lemon *lemp;
13860 @@ -2822,7 +2822,7 @@
13861  PRIVATE FILE *tplt_open(lemp)
13862  struct lemon *lemp;
13863  {
13864 -  
13865 +
13866    char buf[1000];
13867    FILE *in;
13868    char *tpltname;
13869 @@ -2930,7 +2930,7 @@
13870    return ret;
13871  }
13872  
13873 -/* 
13874 +/*
13875  ** Generate code which executes when the rule "rp" is reduced.  Write
13876  ** the code to "out".  Make sure lineno stays up-to-date.
13877  */
13878 @@ -3384,7 +3384,7 @@
13879  
13880    /* Output the yy_shift_ofst[] table */
13881    fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++;
13882 -  fprintf(out, "static %s yy_shift_ofst[] = {\n", 
13883 +  fprintf(out, "static %s yy_shift_ofst[] = {\n",
13884            minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++;
13885    n = lemp->nstate;
13886    for(i=j=0; i<n; i++){
13887 @@ -3405,7 +3405,7 @@
13888  
13889    /* Output the yy_reduce_ofst[] table */
13890    fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++;
13891 -  fprintf(out, "static %s yy_reduce_ofst[] = {\n", 
13892 +  fprintf(out, "static %s yy_reduce_ofst[] = {\n",
13893            minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++;
13894    n = lemp->nstate;
13895    for(i=j=0; i<n; i++){
13896 @@ -3480,7 +3480,7 @@
13897    tplt_xfer(lemp->name,in,out,&lineno);
13898  
13899    /* Generate code which executes every time a symbol is popped from
13900 -  ** the stack while processing errors or while destroying the parser. 
13901 +  ** the stack while processing errors or while destroying the parser.
13902    ** (In other words, generate the %destructor actions)
13903    */
13904    if( lemp->tokendest ){
13905 @@ -3522,7 +3522,7 @@
13906    tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno);
13907    tplt_xfer(lemp->name,in,out,&lineno);
13908  
13909 -  /* Generate the table of rule information 
13910 +  /* Generate the table of rule information
13911    **
13912    ** Note: This code depends on the fact that rules are number
13913    ** sequentually beginning with 0.
13914 @@ -3589,7 +3589,7 @@
13915      for(i=1; i<lemp->nterminal; i++){
13916        fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
13917      }
13918 -    fclose(out);  
13919 +    fclose(out);
13920    }
13921    return;
13922  }
13923 @@ -3630,7 +3630,7 @@
13924          rbest = rp;
13925        }
13926      }
13927
13928 +
13929      /* Do not make a default if the number of rules to default
13930      ** is not at least 2 */
13931      if( nbest<2 ) continue;
13932 @@ -3781,7 +3781,7 @@
13933    if( x1a ){
13934      x1a->size = 1024;
13935      x1a->count = 0;
13936 -    x1a->tbl = (x1node*)malloc( 
13937 +    x1a->tbl = (x1node*)malloc(
13938        (sizeof(x1node) + sizeof(x1node*))*1024 );
13939      if( x1a->tbl==0 ){
13940        free(x1a);
13941 @@ -3943,7 +3943,7 @@
13942    if( x2a ){
13943      x2a->size = 128;
13944      x2a->count = 0;
13945 -    x2a->tbl = (x2node*)malloc( 
13946 +    x2a->tbl = (x2node*)malloc(
13947        (sizeof(x2node) + sizeof(x2node*))*128 );
13948      if( x2a->tbl==0 ){
13949        free(x2a);
13950 @@ -4149,7 +4149,7 @@
13951    if( x3a ){
13952      x3a->size = 128;
13953      x3a->count = 0;
13954 -    x3a->tbl = (x3node*)malloc( 
13955 +    x3a->tbl = (x3node*)malloc(
13956        (sizeof(x3node) + sizeof(x3node*))*128 );
13957      if( x3a->tbl==0 ){
13958        free(x3a);
13959 @@ -4295,7 +4295,7 @@
13960    if( x4a ){
13961      x4a->size = 64;
13962      x4a->count = 0;
13963 -    x4a->tbl = (x4node*)malloc( 
13964 +    x4a->tbl = (x4node*)malloc(
13965        (sizeof(x4node) + sizeof(x4node*))*64 );
13966      if( x4a->tbl==0 ){
13967        free(x4a);
13968 --- ../lighttpd-1.4.11/src/lempar.c     2005-08-11 01:26:40.000000000 +0300
13969 +++ lighttpd-1.4.12/src/lempar.c        2006-07-16 00:26:03.000000000 +0300
13970 @@ -8,10 +8,10 @@
13971  /* Next is all token values, in a form suitable for use by makeheaders.
13972  ** This section will be null unless lemon is run with the -m switch.
13973  */
13974 -/* 
13975 +/*
13976  ** These constants (all generated automatically by the parser generator)
13977  ** specify the various kinds of tokens (terminals) that the parser
13978 -** understands. 
13979 +** understands.
13980  **
13981  ** Each symbol here is a terminal symbol in the grammar.
13982  */
13983 @@ -29,7 +29,7 @@
13984  **                       and nonterminals.  "int" is used otherwise.
13985  **    YYNOCODE           is a number of type YYCODETYPE which corresponds
13986  **                       to no legal terminal or nonterminal number.  This
13987 -**                       number is used to fill in empty slots of the hash 
13988 +**                       number is used to fill in empty slots of the hash
13989  **                       table.
13990  **    YYFALLBACK         If defined, this indicates that one or more tokens
13991  **                       have fall-back values which should be used if the
13992 @@ -38,7 +38,7 @@
13993  **                       and nonterminal numbers.  "unsigned char" is
13994  **                       used if there are fewer than 250 rules and
13995  **                       states combined.  "int" is used otherwise.
13996 -**    ParseTOKENTYPE     is the data type used for minor tokens given 
13997 +**    ParseTOKENTYPE     is the data type used for minor tokens given
13998  **                       directly to the parser from the tokenizer.
13999  **    YYMINORTYPE        is the data type used for all minor tokens.
14000  **                       This is typically a union of many types, one of
14001 @@ -62,7 +62,7 @@
14002  /* Next are that tables used to determine what action to take based on the
14003  ** current state and lookahead token.  These tables are used to implement
14004  ** functions that take a state number and lookahead value and return an
14005 -** action integer.  
14006 +** action integer.
14007  **
14008  ** Suppose the action integer is N.  Then the action is determined as
14009  ** follows
14010 @@ -87,7 +87,7 @@
14011  ** If the index value yy_shift_ofst[S]+X is out of range or if the value
14012  ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
14013  ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
14014 -** and that yy_default[S] should be used instead.  
14015 +** and that yy_default[S] should be used instead.
14016  **
14017  ** The formula above is for computing the action when the lookahead is
14018  ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
14019 @@ -111,7 +111,7 @@
14020  
14021  /* The next table maps tokens into fallback tokens.  If a construct
14022  ** like the following:
14023 -** 
14024 +**
14025  **      %fallback ID X Y Z.
14026  **
14027  ** appears in the grammer, then ID becomes a fallback token for X, Y,
14028 @@ -163,10 +163,10 @@
14029  #endif /* NDEBUG */
14030  
14031  #ifndef NDEBUG
14032 -/* 
14033 +/*
14034  ** Turn parser tracing on by giving a stream to which to write the trace
14035  ** and a prompt to preface each trace message.  Tracing is turned off
14036 -** by making either argument NULL 
14037 +** by making either argument NULL
14038  **
14039  ** Inputs:
14040  ** <ul>
14041 @@ -191,7 +191,7 @@
14042  #ifndef NDEBUG
14043  /* For tracing shifts, the names of all terminals and nonterminals
14044  ** are required.  The following table supplies these names */
14045 -static const char *yyTokenName[] = { 
14046 +static const char *yyTokenName[] = {
14047  %%
14048  };
14049  #endif /* NDEBUG */
14050 @@ -220,7 +220,7 @@
14051  #endif
14052  }
14053  
14054 -/* 
14055 +/*
14056  ** This function allocates a new parser.
14057  ** The only argument is a pointer to a function which works like
14058  ** malloc.
14059 @@ -251,7 +251,7 @@
14060      /* Here is inserted the actions which take place when a
14061      ** terminal or non-terminal is destroyed.  This can happen
14062      ** when the symbol is popped from the stack during a
14063 -    ** reduce or during error processing or when a parser is 
14064 +    ** reduce or during error processing or when a parser is
14065      ** being destroyed before it is finished parsing.
14066      **
14067      ** Note: during a reduce, the only symbols destroyed are those
14068 @@ -289,7 +289,7 @@
14069    return yymajor;
14070  }
14071  
14072 -/* 
14073 +/*
14074  ** Deallocate and destroy a parser.  Destructors are all called for
14075  ** all stack elements before shutting the parser down.
14076  **
14077 @@ -325,7 +325,7 @@
14078  ){
14079    int i;
14080    int stateno = pParser->yystack[pParser->yyidx].stateno;
14081
14082 +
14083    /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
14084    i = yy_shift_ofst[stateno];
14085    if( i==YY_SHIFT_USE_DFLT ){
14086 @@ -369,7 +369,7 @@
14087  ){
14088    int i;
14089    int stateno = pParser->yystack[pParser->yyidx].stateno;
14090
14091 +
14092    i = yy_reduce_ofst[stateno];
14093    if( i==YY_REDUCE_USE_DFLT ){
14094      return yy_default[stateno];
14095 @@ -455,7 +455,7 @@
14096    ParseARG_FETCH;
14097    yymsp = &yypParser->yystack[yypParser->yyidx];
14098  #ifndef NDEBUG
14099 -  if( yyTraceFILE && yyruleno>=0 
14100 +  if( yyTraceFILE && yyruleno>=0
14101          && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
14102      fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
14103        yyRuleName[yyruleno]);
14104 @@ -608,7 +608,7 @@
14105  #ifdef YYERRORSYMBOL
14106        /* A syntax error has occurred.
14107        ** The response to an error depends upon whether or not the
14108 -      ** grammar defines an error token "ERROR".  
14109 +      ** grammar defines an error token "ERROR".
14110        **
14111        ** This is what we do if the grammar does define ERROR:
14112        **
14113 --- ../lighttpd-1.4.11/src/log.c        2005-11-07 15:01:35.000000000 +0200
14114 +++ lighttpd-1.4.12/src/log.c   2006-07-18 13:03:40.000000000 +0300
14115 @@ -5,7 +5,6 @@
14116  #include <errno.h>
14117  #include <fcntl.h>
14118  #include <time.h>
14119 -#include <unistd.h>
14120  #include <string.h>
14121  #include <stdlib.h>
14122  
14123 @@ -16,6 +15,10 @@
14124  #include "config.h"
14125  #endif
14126  
14127 +#ifdef _WIN32
14128 +#undef HAVE_SYSLOG_H
14129 +#endif
14130 +
14131  #ifdef HAVE_SYSLOG_H
14132  #include <syslog.h>
14133  #endif
14134 @@ -23,6 +26,8 @@
14135  #include "log.h"
14136  #include "array.h"
14137  
14138 +#include "sys-files.h"
14139 +
14140  #ifdef HAVE_VALGRIND_VALGRIND_H
14141  #include <valgrind/valgrind.h>
14142  #endif
14143 @@ -31,55 +36,114 @@
14144  # define O_LARGEFILE 0
14145  #endif
14146  
14147 -/** 
14148 +/**
14149   * open the errorlog
14150 - * 
14151 + *
14152   * we have 3 possibilities:
14153   * - stderr (default)
14154 - * - syslog 
14155 + * - syslog
14156   * - logfile
14157 - * 
14158 + *
14159   * if the open failed, report to the user and die
14160 - * 
14161 + *
14162   */
14163  
14164 -int log_error_open(server *srv) {
14165 +
14166 +typedef struct {
14167 +       buffer *file;
14168 +       unsigned short use_syslog;
14169 +
14170 +       /* the errorlog */
14171         int fd;
14172 -       int close_stderr = 1;
14173 +       enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } mode;
14174 +       buffer *buf;
14175 +
14176 +       time_t cached_ts;
14177 +       buffer *cached_ts_str;
14178 +} errorlog;
14179 +
14180 +errorlog *myconfig = NULL;
14181 +
14182 +void log_init(void) {
14183 +       /* use syslog */
14184 +       errorlog *err;
14185 +
14186 +       err = calloc(1, sizeof(*err));
14187         
14188 +       err->fd = -1;
14189 +       err->mode = ERRORLOG_STDERR;
14190 +       err->buf = buffer_init();
14191 +       err->cached_ts_str = buffer_init();
14192 +
14193 +       myconfig = err;
14194 +}
14195 +
14196 +void log_free(void) {
14197 +       errorlog *err = myconfig;
14198 +
14199 +       if (!err) return;
14200 +
14201 +       TRACE("%s", "server stopped");
14202 +
14203 +       switch(err->mode) {
14204 +       case ERRORLOG_FILE:
14205 +               close(err->fd);
14206 +               break;
14207 +       case ERRORLOG_SYSLOG:
14208 +#ifdef HAVE_SYSLOG_H
14209 +               closelog();
14210 +#endif
14211 +               break;
14212 +       case ERRORLOG_STDERR:
14213 +               break;
14214 +       }
14215 +
14216 +       buffer_free(err->buf);
14217 +       buffer_free(err->cached_ts_str);
14218 +       if (err->file) buffer_free(err->file);
14219 +
14220 +       free(err);
14221 +
14222 +       myconfig = NULL;
14223 +}
14224 +
14225 +int log_error_open(buffer *file, int use_syslog) {
14226 +       int fd;
14227 +       int close_stderr = 1;
14228 +
14229 +       errorlog *err = myconfig;
14230 +
14231  #ifdef HAVE_SYSLOG_H
14232         /* perhaps someone wants to use syslog() */
14233         openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON);
14234  #endif
14235 -       srv->errorlog_mode = ERRORLOG_STDERR;
14236 -       
14237 -       if (srv->srvconf.errorlog_use_syslog) {
14238 -               srv->errorlog_mode = ERRORLOG_SYSLOG;
14239 -       } else if (!buffer_is_empty(srv->srvconf.errorlog_file)) {
14240 -               const char *logfile = srv->srvconf.errorlog_file->ptr;
14241 -               
14242 -               if (-1 == (srv->errorlog_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14243 -                       log_error_write(srv, __FILE__, __LINE__, "SSSS", 
14244 -                                       "opening errorlog '", logfile,
14245 +       err->mode = ERRORLOG_STDERR;
14246 +
14247 +       if (use_syslog) {
14248 +               err->mode = ERRORLOG_SYSLOG;
14249 +       } else if (!buffer_is_empty(file)) {
14250 +               if (-1 == (err->fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14251 +                       log_error_write(NULL, __FILE__, __LINE__, "SBSS",
14252 +                                       "opening errorlog '", file,
14253                                         "' failed: ", strerror(errno));
14254 -                       
14255 +
14256                         return -1;
14257                 }
14258  #ifdef FD_CLOEXEC
14259                 /* close fd on exec (cgi) */
14260 -               fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC);
14261 +               fcntl(err->fd, F_SETFD, FD_CLOEXEC);
14262  #endif
14263 -               srv->errorlog_mode = ERRORLOG_FILE;
14264 +               err->mode = ERRORLOG_FILE;
14265         }
14266 -       
14267 -       log_error_write(srv, __FILE__, __LINE__, "s", "server started");
14268 -       
14269 +
14270 +       TRACE("%s", "server started");
14271 +
14272  #ifdef HAVE_VALGRIND_VALGRIND_H
14273         /* don't close stderr for debugging purposes if run in valgrind */
14274         if (RUNNING_ON_VALGRIND) close_stderr = 0;
14275  #endif
14276 -       if (srv->errorlog_mode == ERRORLOG_STDERR) close_stderr = 0;
14277 -       
14278 +       if (err->mode == ERRORLOG_STDERR) close_stderr = 0;
14279 +
14280         /* move stderr to /dev/null */
14281         if (close_stderr &&
14282             -1 != (fd = open("/dev/null", O_WRONLY))) {
14283 @@ -90,167 +154,202 @@
14284         return 0;
14285  }
14286  
14287 -/** 
14288 +/**
14289   * open the errorlog
14290 - * 
14291 + *
14292   * if the open failed, report to the user and die
14293   * if no filename is given, use syslog instead
14294 - * 
14295 + *
14296   */
14297  
14298 -int log_error_cycle(server *srv) {
14299 +int log_error_cycle(void) {
14300         /* only cycle if we are not in syslog-mode */
14301 -       
14302 -       if (srv->errorlog_mode == ERRORLOG_FILE) {
14303 -               const char *logfile = srv->srvconf.errorlog_file->ptr;
14304 +
14305 +       errorlog *err = myconfig;
14306 +
14307 +       if (err->mode == ERRORLOG_FILE) {
14308 +               buffer *file = err->file;
14309                 /* already check of opening time */
14310 -               
14311 +
14312                 int new_fd;
14313 -               
14314 -               if (-1 == (new_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14315 +
14316 +               if (-1 == (new_fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14317                         /* write to old log */
14318 -                       log_error_write(srv, __FILE__, __LINE__, "SSSSS", 
14319 -                                       "cycling errorlog '", logfile,
14320 +                       log_error_write(NULL, __FILE__, __LINE__, "SBSSS",
14321 +                                       "cycling errorlog '", file,
14322                                         "' failed: ", strerror(errno),
14323                                         ", falling back to syslog()");
14324 -                       
14325 -                       close(srv->errorlog_fd);
14326 -                       srv->errorlog_fd = -1;
14327 -#ifdef HAVE_SYSLOG_H   
14328 -                       srv->errorlog_mode = ERRORLOG_SYSLOG;
14329 +
14330 +                       close(err->fd);
14331 +                       err->fd = -1;
14332 +#ifdef HAVE_SYSLOG_H
14333 +                       err->mode = ERRORLOG_SYSLOG;
14334  #endif
14335                 } else {
14336                         /* ok, new log is open, close the old one */
14337 -                       close(srv->errorlog_fd);
14338 -                       srv->errorlog_fd = new_fd;
14339 +                       close(err->fd);
14340 +                       err->fd = new_fd;
14341                 }
14342         }
14343 -       
14344 -       log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled");
14345 -       
14346 -       return 0;
14347 -}
14348  
14349 -int log_error_close(server *srv) {
14350 -       log_error_write(srv, __FILE__, __LINE__, "s", "server stopped");
14351 -       
14352 -       switch(srv->errorlog_mode) {
14353 -       case ERRORLOG_FILE:
14354 -               close(srv->errorlog_fd);
14355 -               break;
14356 -       case ERRORLOG_SYSLOG:
14357 -#ifdef HAVE_SYSLOG_H
14358 -               closelog();
14359 -#endif
14360 -               break;
14361 -       case ERRORLOG_STDERR:
14362 -               break;
14363 -       }
14364 -       
14365 +       TRACE("%s", "logfiles cycled");
14366 +
14367         return 0;
14368  }
14369  
14370 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
14371 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...) {
14372         va_list ap;
14373 -       
14374 -       switch(srv->errorlog_mode) {
14375 +       time_t t;
14376 +
14377 +       errorlog *err = myconfig;
14378 +
14379 +       switch(err->mode) {
14380         case ERRORLOG_FILE:
14381         case ERRORLOG_STDERR:
14382                 /* cache the generated timestamp */
14383 -               if (srv->cur_ts != srv->last_generated_debug_ts) {
14384 -                       buffer_prepare_copy(srv->ts_debug_str, 255);
14385 -                       strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
14386 -                       srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1;
14387 -                       
14388 -                       srv->last_generated_debug_ts = srv->cur_ts;
14389 +               t = time(NULL);
14390 +               
14391 +               if (t != err->cached_ts) {
14392 +                       buffer_prepare_copy(err->cached_ts_str, 255);
14393 +                       strftime(err->cached_ts_str->ptr, err->cached_ts_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(t)));
14394 +                       err->cached_ts_str->used = strlen(err->cached_ts_str->ptr) + 1;
14395 +                       err->cached_ts = t;
14396                 }
14397  
14398 -               buffer_copy_string_buffer(srv->errorlog_buf, srv->ts_debug_str);
14399 -               BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ": (");
14400 +               buffer_copy_string_buffer(err->buf, err->cached_ts_str);
14401 +               BUFFER_APPEND_STRING_CONST(err->buf, ": (");
14402                 break;
14403         case ERRORLOG_SYSLOG:
14404                 /* syslog is generating its own timestamps */
14405 -               BUFFER_COPY_STRING_CONST(srv->errorlog_buf, "(");
14406 +               BUFFER_COPY_STRING_CONST(err->buf, "(");
14407                 break;
14408         }
14409 -       
14410 -       buffer_append_string(srv->errorlog_buf, filename);
14411 -       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ".");
14412 -       buffer_append_long(srv->errorlog_buf, line);
14413 -       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ") ");
14414 -       
14415 -       
14416 +
14417 +       buffer_append_string(err->buf, filename);
14418 +       BUFFER_APPEND_STRING_CONST(err->buf, ".");
14419 +       buffer_append_long(err->buf, line);
14420 +       BUFFER_APPEND_STRING_CONST(err->buf, ") ");
14421 +
14422         for(va_start(ap, fmt); *fmt; fmt++) {
14423                 int d;
14424                 char *s;
14425                 buffer *b;
14426                 off_t o;
14427 -               
14428 +
14429                 switch(*fmt) {
14430                 case 's':           /* string */
14431                         s = va_arg(ap, char *);
14432 -                       buffer_append_string(srv->errorlog_buf, s);
14433 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14434 +                       buffer_append_string(err->buf, s);
14435 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14436                         break;
14437                 case 'b':           /* buffer */
14438                         b = va_arg(ap, buffer *);
14439 -                       buffer_append_string_buffer(srv->errorlog_buf, b);
14440 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14441 +                       buffer_append_string_buffer(err->buf, b);
14442 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14443                         break;
14444                 case 'd':           /* int */
14445                         d = va_arg(ap, int);
14446 -                       buffer_append_long(srv->errorlog_buf, d);
14447 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14448 +                       buffer_append_long(err->buf, d);
14449 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14450                         break;
14451                 case 'o':           /* off_t */
14452                         o = va_arg(ap, off_t);
14453 -                       buffer_append_off_t(srv->errorlog_buf, o);
14454 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14455 +                       buffer_append_off_t(err->buf, o);
14456 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14457                         break;
14458                 case 'x':           /* int (hex) */
14459                         d = va_arg(ap, int);
14460 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "0x");
14461 -                       buffer_append_long_hex(srv->errorlog_buf, d);
14462 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14463 +                       BUFFER_APPEND_STRING_CONST(err->buf, "0x");
14464 +                       buffer_append_long_hex(err->buf, d);
14465 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14466                         break;
14467                 case 'S':           /* string */
14468                         s = va_arg(ap, char *);
14469 -                       buffer_append_string(srv->errorlog_buf, s);
14470 +                       buffer_append_string(err->buf, s);
14471                         break;
14472                 case 'B':           /* buffer */
14473                         b = va_arg(ap, buffer *);
14474 -                       buffer_append_string_buffer(srv->errorlog_buf, b);
14475 +                       buffer_append_string_buffer(err->buf, b);
14476                         break;
14477                 case 'D':           /* int */
14478                         d = va_arg(ap, int);
14479 -                       buffer_append_long(srv->errorlog_buf, d);
14480 +                       buffer_append_long(err->buf, d);
14481                         break;
14482                 case '(':
14483                 case ')':
14484 -               case '<':       
14485 +               case '<':
14486                 case '>':
14487                 case ',':
14488                 case ' ':
14489 -                       buffer_append_string_len(srv->errorlog_buf, fmt, 1);
14490 +                       buffer_append_string_len(err->buf, fmt, 1);
14491                         break;
14492                 }
14493         }
14494         va_end(ap);
14495 -       
14496 -       switch(srv->errorlog_mode) {
14497 +
14498 +       switch(err->mode) {
14499         case ERRORLOG_FILE:
14500 -               BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
14501 -               write(srv->errorlog_fd, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
14502 +               BUFFER_APPEND_STRING_CONST(err->buf, "\n");
14503 +               write(err->fd, err->buf->ptr, err->buf->used - 1);
14504                 break;
14505         case ERRORLOG_STDERR:
14506 -               BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
14507 -               write(STDERR_FILENO, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
14508 +               BUFFER_APPEND_STRING_CONST(err->buf, "\n");
14509 +               write(STDERR_FILENO, err->buf->ptr, err->buf->used - 1);
14510                 break;
14511 +#ifdef HAVE_SYSLOG_H
14512 +       case ERRORLOG_SYSLOG:
14513 +               syslog(LOG_ERR, "%s", err->buf->ptr);
14514 +               break;
14515 +#endif
14516 +       }
14517 +
14518 +       return 0;
14519 +}
14520 +
14521 +static int log_trace_write(const char *fmt, va_list ap) {
14522 +       buffer *b;
14523 +       int l;
14524 +       errorlog *err = myconfig;
14525 +       
14526 +       b = buffer_init();
14527 +       buffer_prepare_copy(b, 1024);
14528 +       l = vsnprintf(b->ptr, b->size - 1, fmt, ap);
14529 +       if (l > 0) {
14530 +               b->used = (l > b->size - 1) ? b->size : l + 1;
14531 +       }
14532 +
14533 +       /* write b */
14534 +       switch(err->mode) {
14535 +       case ERRORLOG_FILE:
14536 +               buffer_append_string(b, "\r\n");
14537 +               write(err->fd, b->ptr, b->used - 1);
14538 +               break;
14539 +       case ERRORLOG_STDERR:
14540 +               buffer_append_string(b, "\r\n");
14541 +               write(STDERR_FILENO, b->ptr, b->used - 1);
14542 +               break;
14543 +#ifdef HAVE_SYSLOG_H
14544         case ERRORLOG_SYSLOG:
14545 -               syslog(LOG_ERR, "%s", srv->errorlog_buf->ptr);
14546 +               syslog(LOG_ERR, "%s", b->ptr);
14547                 break;
14548 +#endif
14549         }
14550         
14551 +       buffer_free(b);
14552 +
14553 +       return 0;
14554 +}
14555 +
14556 +int log_trace(const char *fmt, ...) {
14557 +       va_list ap;
14558 +
14559 +       va_start(ap, fmt);
14560 +
14561 +       log_trace_write(fmt, ap);
14562 +
14563 +       va_end(ap);
14564 +
14565         return 0;
14566  }
14567  
14568 +
14569 --- ../lighttpd-1.4.11/src/log.h        2005-08-11 01:26:36.000000000 +0300
14570 +++ lighttpd-1.4.12/src/log.h   2006-07-18 13:03:40.000000000 +0300
14571 @@ -1,13 +1,22 @@
14572  #ifndef _LOG_H_
14573  #define _LOG_H_
14574  
14575 -#include "server.h"
14576 +#include "buffer.h"
14577  
14578 -#define WP() log_error_write(srv, __FILE__, __LINE__, "");
14579 +void log_init(void); 
14580 +void log_free(void); 
14581  
14582 -int log_error_open(server *srv);
14583 -int log_error_close(server *srv);
14584 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...);
14585 -int log_error_cycle(server *srv);
14586 -       
14587 +int log_error_open(buffer *file, int use_syslog);
14588 +int log_error_close();
14589 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...);
14590 +int log_error_cycle();
14591 +
14592 +#define ERROR(fmt, ...) \
14593 +       log_trace("%s.%d: (error) "fmt, __FILE__, __LINE__, __VA_ARGS__)
14594 +
14595 +#define TRACE(fmt, ...) \
14596 +       log_trace("%s.%d: (trace) "fmt, __FILE__, __LINE__, __VA_ARGS__)
14597 +
14598 +#define SEGFAULT() do { ERROR("%s", "Ooh, Ooh, Ooh. Something is not good ... going down"); abort(); } while(0)
14599 +int log_trace(const char *fmt, ...);
14600  #endif
14601 --- ../lighttpd-1.4.11/src/md5.h        2005-11-17 16:20:40.000000000 +0200
14602 +++ lighttpd-1.4.12/src/md5.h   2006-07-16 00:26:04.000000000 +0300
14603 @@ -30,9 +30,15 @@
14604  # include <inttypes.h>
14605  #endif
14606  
14607 +#ifdef _WIN32
14608 +#define UINT4 unsigned __int32
14609 +#define UINT2 unsigned __int16
14610 +#define POINTER unsigned char *
14611 +#else
14612  #define UINT4 uint32_t
14613  #define UINT2 uint16_t
14614  #define POINTER unsigned char *
14615 +#endif
14616  
14617  /* MD5 context. */
14618  typedef struct {
14619 --- ../lighttpd-1.4.11/src/mod_access.c 2006-01-14 19:44:54.000000000 +0200
14620 +++ lighttpd-1.4.12/src/mod_access.c    2006-07-16 00:26:04.000000000 +0300
14621 @@ -8,126 +8,125 @@
14622  
14623  #include "plugin.h"
14624  
14625 +#include "sys-strings.h"
14626 +
14627  typedef struct {
14628         array *access_deny;
14629  } plugin_config;
14630  
14631  typedef struct {
14632         PLUGIN_DATA;
14633 -       
14634 +
14635         plugin_config **config_storage;
14636 -       
14637 -       plugin_config conf; 
14638 +
14639 +       plugin_config conf;
14640  } plugin_data;
14641  
14642  INIT_FUNC(mod_access_init) {
14643         plugin_data *p;
14644 -       
14645 +
14646         p = calloc(1, sizeof(*p));
14647 -       
14648 +
14649         return p;
14650  }
14651  
14652  FREE_FUNC(mod_access_free) {
14653         plugin_data *p = p_d;
14654 -       
14655 +
14656         UNUSED(srv);
14657  
14658         if (!p) return HANDLER_GO_ON;
14659 -       
14660 +
14661         if (p->config_storage) {
14662                 size_t i;
14663                 for (i = 0; i < srv->config_context->used; i++) {
14664                         plugin_config *s = p->config_storage[i];
14665 -                       
14666 +
14667                         array_free(s->access_deny);
14668 -                       
14669 +
14670                         free(s);
14671                 }
14672                 free(p->config_storage);
14673         }
14674 -       
14675 +
14676         free(p);
14677 -       
14678 +
14679         return HANDLER_GO_ON;
14680  }
14681  
14682  SETDEFAULTS_FUNC(mod_access_set_defaults) {
14683         plugin_data *p = p_d;
14684         size_t i = 0;
14685 -       
14686 -       config_values_t cv[] = { 
14687 +
14688 +       config_values_t cv[] = {
14689                 { "url.access-deny",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
14690                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
14691         };
14692 -       
14693 +
14694         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
14695 -       
14696 +
14697         for (i = 0; i < srv->config_context->used; i++) {
14698                 plugin_config *s;
14699 -               
14700 +
14701                 s = calloc(1, sizeof(plugin_config));
14702                 s->access_deny    = array_init();
14703 -               
14704 +
14705                 cv[0].destination = s->access_deny;
14706 -               
14707 +
14708                 p->config_storage[i] = s;
14709 -       
14710 +
14711                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
14712                         return HANDLER_ERROR;
14713                 }
14714         }
14715 -       
14716 +
14717         return HANDLER_GO_ON;
14718  }
14719  
14720 -#define PATCH(x) \
14721 -       p->conf.x = s->x;
14722  static int mod_access_patch_connection(server *srv, connection *con, plugin_data *p) {
14723         size_t i, j;
14724         plugin_config *s = p->config_storage[0];
14725  
14726 -       PATCH(access_deny);
14727 -       
14728 +       PATCH_OPTION(access_deny);
14729 +
14730         /* skip the first, the global context */
14731         for (i = 1; i < srv->config_context->used; i++) {
14732                 data_config *dc = (data_config *)srv->config_context->data[i];
14733                 s = p->config_storage[i];
14734 -               
14735 +
14736                 /* condition didn't match */
14737                 if (!config_check_cond(srv, con, dc)) continue;
14738 -               
14739 +
14740                 /* merge config */
14741                 for (j = 0; j < dc->value->used; j++) {
14742                         data_unset *du = dc->value->data[j];
14743 -                       
14744 +
14745                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.access-deny"))) {
14746 -                               PATCH(access_deny);
14747 +                               PATCH_OPTION(access_deny);
14748                         }
14749                 }
14750         }
14751 -       
14752 +
14753         return 0;
14754  }
14755 -#undef PATCH
14756  
14757  URIHANDLER_FUNC(mod_access_uri_handler) {
14758         plugin_data *p = p_d;
14759         int s_len;
14760         size_t k;
14761 -       
14762 +
14763         if (con->uri.path->used == 0) return HANDLER_GO_ON;
14764 -       
14765 +
14766         mod_access_patch_connection(srv, con, p);
14767 -       
14768 +
14769         s_len = con->uri.path->used - 1;
14770 -       
14771 +
14772         for (k = 0; k < p->conf.access_deny->used; k++) {
14773                 data_string *ds = (data_string *)p->conf.access_deny->data[k];
14774                 int ct_len = ds->value->used - 1;
14775 -               
14776 +
14777                 if (ct_len > s_len) continue;
14778 -               
14779 +
14780                 if (ds->value->used == 0) continue;
14781  
14782                 /* if we have a case-insensitive FS we have to lower-case the URI here too */
14783 @@ -135,18 +134,18 @@
14784                 if (con->conf.force_lowercase_filenames) {
14785                         if (0 == strncasecmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
14786                                 con->http_status = 403;
14787 -                       
14788 +
14789                                 return HANDLER_FINISHED;
14790                         }
14791                 } else {
14792                         if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
14793                                 con->http_status = 403;
14794 -                       
14795 +
14796                                 return HANDLER_FINISHED;
14797                         }
14798                 }
14799         }
14800 -       
14801 +
14802         /* not found */
14803         return HANDLER_GO_ON;
14804  }
14805 @@ -155,13 +154,13 @@
14806  int mod_access_plugin_init(plugin *p) {
14807         p->version     = LIGHTTPD_VERSION_ID;
14808         p->name        = buffer_init_string("access");
14809 -       
14810 +
14811         p->init        = mod_access_init;
14812         p->set_defaults = mod_access_set_defaults;
14813         p->handle_uri_clean  = mod_access_uri_handler;
14814         p->cleanup     = mod_access_free;
14815 -       
14816 +
14817         p->data        = NULL;
14818 -       
14819 +
14820         return 0;
14821  }
14822 --- ../lighttpd-1.4.11/src/mod_accesslog.c      2006-01-31 14:01:43.000000000 +0200
14823 +++ lighttpd-1.4.12/src/mod_accesslog.c 2006-07-16 00:26:04.000000000 +0300
14824 @@ -6,8 +6,7 @@
14825  #include <ctype.h>
14826  #include <stdlib.h>
14827  #include <string.h>
14828 -#include <fcntl.h>
14829 -#include <unistd.h>
14830 +#include <fcntl.h> /* only the defines on windows */
14831  #include <errno.h>
14832  #include <time.h>
14833  
14834 @@ -22,6 +21,7 @@
14835  #include "inet_ntop_cache.h"
14836  
14837  #include "sys-socket.h"
14838 +#include "sys-files.h"
14839  
14840  #ifdef HAVE_SYSLOG_H
14841  # include <syslog.h>
14842 @@ -29,7 +29,7 @@
14843  
14844  typedef struct {
14845         char key;
14846 -       enum { 
14847 +       enum {
14848                 FORMAT_UNSET,
14849                         FORMAT_UNSUPPORTED,
14850                         FORMAT_PERCENT,
14851 @@ -41,7 +41,7 @@
14852                         FORMAT_STATUS,
14853                         FORMAT_BYTES_OUT_NO_HEADER,
14854                         FORMAT_HEADER,
14855 -                       
14856 +
14857                         FORMAT_REMOTE_ADDR,
14858                         FORMAT_LOCAL_ADDR,
14859                         FORMAT_COOKIE,
14860 @@ -59,20 +59,20 @@
14861                         FORMAT_CONNECTION_STATUS,
14862                         FORMAT_BYTES_IN,
14863                         FORMAT_BYTES_OUT,
14864 -                       
14865 +
14866                         FORMAT_RESPONSE_HEADER
14867         } type;
14868  } format_mapping;
14869  
14870  /**
14871 - * 
14872 - * 
14873 + *
14874 + *
14875   * "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
14876 - * 
14877 + *
14878   */
14879  
14880 -const format_mapping fmap[] = 
14881 -{ 
14882 +const format_mapping fmap[] =
14883 +{
14884         { '%', FORMAT_PERCENT },
14885         { 'h', FORMAT_REMOTE_HOST },
14886         { 'l', FORMAT_REMOTE_IDENT },
14887 @@ -82,7 +82,7 @@
14888         { 's', FORMAT_STATUS },
14889         { 'b', FORMAT_BYTES_OUT_NO_HEADER },
14890         { 'i', FORMAT_HEADER },
14891 -       
14892 +
14893         { 'a', FORMAT_REMOTE_ADDR },
14894         { 'A', FORMAT_LOCAL_ADDR },
14895         { 'B', FORMAT_BYTES_OUT_NO_HEADER },
14896 @@ -103,23 +103,23 @@
14897         { 'X', FORMAT_CONNECTION_STATUS },
14898         { 'I', FORMAT_BYTES_IN },
14899         { 'O', FORMAT_BYTES_OUT },
14900 -       
14901 +
14902         { 'o', FORMAT_RESPONSE_HEADER },
14903 -       
14904 +
14905         { '\0', FORMAT_UNSET }
14906  };
14907  
14908  
14909  typedef struct {
14910         enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type;
14911 -       
14912 +
14913         buffer *string;
14914         int field;
14915  } format_field;
14916  
14917  typedef struct {
14918         format_field **ptr;
14919 -       
14920 +
14921         size_t used;
14922         size_t size;
14923  } format_fields;
14924 @@ -128,39 +128,39 @@
14925         buffer *access_logfile;
14926         buffer *format;
14927         unsigned short use_syslog;
14928 -       
14929 -       
14930 +
14931 +
14932         int    log_access_fd;
14933         time_t last_generated_accesslog_ts;
14934         time_t *last_generated_accesslog_ts_ptr;
14935 -       
14936 -       
14937 +
14938 +
14939         buffer *access_logbuffer;
14940         buffer *ts_accesslog_str;
14941 -       
14942 +
14943         format_fields *parsed_format;
14944  } plugin_config;
14945  
14946  typedef struct {
14947         PLUGIN_DATA;
14948 -       
14949 +
14950         plugin_config **config_storage;
14951 -       plugin_config conf; 
14952 +       plugin_config conf;
14953  } plugin_data;
14954  
14955  INIT_FUNC(mod_accesslog_init) {
14956         plugin_data *p;
14957 -       
14958 +
14959         p = calloc(1, sizeof(*p));
14960 -       
14961 +
14962         return p;
14963  }
14964  
14965  int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
14966         size_t i, j, k = 0, start = 0;
14967 -       
14968 +
14969         for (i = 0; i < format->used - 1; i++) {
14970 -               
14971 +
14972                 switch(format->ptr[i]) {
14973                 case '%':
14974                         if (start != i) {
14975 @@ -173,19 +173,19 @@
14976                                         fields->size += 16;
14977                                         fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
14978                                 }
14979 -                               
14980 +
14981                                 fields->ptr[fields->used] = malloc(sizeof(format_fields));
14982                                 fields->ptr[fields->used]->type = FIELD_STRING;
14983                                 fields->ptr[fields->used]->string = buffer_init();
14984 -                               
14985 +
14986                                 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
14987 -                               
14988 +
14989                                 fields->used++;
14990                         }
14991 -                       
14992 -                       
14993 +
14994 +
14995                         /* we need a new field */
14996 -                       
14997 +
14998                         if (fields->size == 0) {
14999                                 fields->size = 16;
15000                                 fields->used = 0;
15001 @@ -194,43 +194,43 @@
15002                                 fields->size += 16;
15003                                 fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
15004                         }
15005 -                       
15006 +
15007                         /* search for the terminating command */
15008                         switch (format->ptr[i+1]) {
15009                         case '>':
15010                         case '<':
15011                                 /* only for s */
15012 -                               
15013 +
15014                                 for (j = 0; fmap[j].key != '\0'; j++) {
15015                                         if (fmap[j].key != format->ptr[i+2]) continue;
15016 -                                       
15017 +
15018                                         /* found key */
15019 -                                               
15020 +
15021                                         fields->ptr[fields->used] = malloc(sizeof(format_fields));
15022                                         fields->ptr[fields->used]->type = FIELD_FORMAT;
15023                                         fields->ptr[fields->used]->field = fmap[j].type;
15024                                         fields->ptr[fields->used]->string = NULL;
15025 -                                       
15026 +
15027                                         fields->used++;
15028 -                                       
15029 +
15030                                         break;
15031                                 }
15032 -                               
15033 +
15034                                 if (fmap[j].key == '\0') {
15035                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15036                                         return -1;
15037                                 }
15038 -                               
15039 +
15040                                 start = i + 3;
15041 -                               
15042 +
15043                                 break;
15044                         case '{':
15045                                 /* go forward to } */
15046 -                               
15047 +
15048                                 for (k = i+2; k < format->used - 1; k++) {
15049                                         if (format->ptr[k] == '}') break;
15050                                 }
15051 -                               
15052 +
15053                                 if (k == format->used - 1) {
15054                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15055                                         return -1;
15056 @@ -239,62 +239,62 @@
15057                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15058                                         return -1;
15059                                 }
15060 -                               
15061 +
15062                                 for (j = 0; fmap[j].key != '\0'; j++) {
15063                                         if (fmap[j].key != format->ptr[k+1]) continue;
15064 -                                       
15065 +
15066                                         /* found key */
15067 -                                               
15068 +
15069                                         fields->ptr[fields->used] = malloc(sizeof(format_fields));
15070                                         fields->ptr[fields->used]->type = FIELD_FORMAT;
15071                                         fields->ptr[fields->used]->field = fmap[j].type;
15072                                         fields->ptr[fields->used]->string = buffer_init();
15073 -                                       
15074 +
15075                                         buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + i + 2, k - (i + 2));
15076 -                                       
15077 +
15078                                         fields->used++;
15079 -                                       
15080 +
15081                                         break;
15082                                 }
15083 -                               
15084 +
15085                                 if (fmap[j].key == '\0') {
15086                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15087                                         return -1;
15088                                 }
15089 -                               
15090 +
15091                                 start = k + 2;
15092 -                               
15093 +
15094                                 break;
15095                         default:
15096                                 for (j = 0; fmap[j].key != '\0'; j++) {
15097                                         if (fmap[j].key != format->ptr[i+1]) continue;
15098 -                                       
15099 +
15100                                         /* found key */
15101 -                                               
15102 +
15103                                         fields->ptr[fields->used] = malloc(sizeof(format_fields));
15104                                         fields->ptr[fields->used]->type = FIELD_FORMAT;
15105                                         fields->ptr[fields->used]->field = fmap[j].type;
15106                                         fields->ptr[fields->used]->string = NULL;
15107 -                                       
15108 +
15109                                         fields->used++;
15110 -                                       
15111 +
15112                                         break;
15113                                 }
15114 -                               
15115 +
15116                                 if (fmap[j].key == '\0') {
15117                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15118                                         return -1;
15119                                 }
15120 -                               
15121 +
15122                                 start = i + 2;
15123 -                               
15124 +
15125                                 break;
15126                         }
15127 -                       
15128 +
15129                         break;
15130                 }
15131         }
15132 -       
15133 +
15134         if (start < i) {
15135                 /* copy the string */
15136                 if (fields->size == 0) {
15137 @@ -305,32 +305,32 @@
15138                         fields->size += 16;
15139                         fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
15140                 }
15141 -               
15142 +
15143                 fields->ptr[fields->used] = malloc(sizeof(format_fields));
15144                 fields->ptr[fields->used]->type = FIELD_STRING;
15145                 fields->ptr[fields->used]->string = buffer_init();
15146 -               
15147 +
15148                 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
15149 -               
15150 +
15151                 fields->used++;
15152         }
15153 -       
15154 +
15155         return 0;
15156  }
15157  
15158  FREE_FUNC(mod_accesslog_free) {
15159         plugin_data *p = p_d;
15160         size_t i;
15161 -       
15162 +
15163         if (!p) return HANDLER_GO_ON;
15164 -       
15165 +
15166         if (p->config_storage) {
15167 -               
15168 +
15169                 for (i = 0; i < srv->config_context->used; i++) {
15170                         plugin_config *s = p->config_storage[i];
15171  
15172                         if (!s) continue;
15173 -                       
15174 +
15175                         if (s->access_logbuffer->used) {
15176                                 if (s->use_syslog) {
15177  # ifdef HAVE_SYSLOG_H
15178 @@ -342,14 +342,14 @@
15179                                         write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
15180                                 }
15181                         }
15182 -                       
15183 +
15184                         if (s->log_access_fd != -1) close(s->log_access_fd);
15185 -                       
15186 +
15187                         buffer_free(s->ts_accesslog_str);
15188                         buffer_free(s->access_logbuffer);
15189                         buffer_free(s->format);
15190                         buffer_free(s->access_logfile);
15191 -                       
15192 +
15193                         if (s->parsed_format) {
15194                                 size_t j;
15195                                 for (j = 0; j < s->parsed_format->used; j++) {
15196 @@ -359,36 +359,36 @@
15197                                 free(s->parsed_format->ptr);
15198                                 free(s->parsed_format);
15199                         }
15200 -                       
15201 +
15202                         free(s);
15203                 }
15204 -       
15205 +
15206                 free(p->config_storage);
15207         }
15208 -       
15209 +
15210         free(p);
15211 -       
15212 +
15213         return HANDLER_GO_ON;
15214  }
15215  
15216  SETDEFAULTS_FUNC(log_access_open) {
15217         plugin_data *p = p_d;
15218         size_t i = 0;
15219 -       
15220 -       config_values_t cv[] = { 
15221 +
15222 +       config_values_t cv[] = {
15223                 { "accesslog.filename",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
15224                 { "accesslog.use-syslog",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
15225                 { "accesslog.format",               NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
15226                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
15227         };
15228 -       
15229 +
15230         if (!p) return HANDLER_ERROR;
15231 -       
15232 +
15233         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
15234 -       
15235 +
15236         for (i = 0; i < srv->config_context->used; i++) {
15237                 plugin_config *s;
15238 -               
15239 +
15240                 s = calloc(1, sizeof(plugin_config));
15241                 s->access_logfile = buffer_init();
15242                 s->format = buffer_init();
15243 @@ -397,44 +397,44 @@
15244                 s->log_access_fd = -1;
15245                 s->last_generated_accesslog_ts = 0;
15246                 s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts);
15247 -               
15248 -       
15249 +
15250 +
15251                 cv[0].destination = s->access_logfile;
15252                 cv[1].destination = &(s->use_syslog);
15253                 cv[2].destination = s->format;
15254 -       
15255 +
15256                 p->config_storage[i] = s;
15257 -               
15258 +
15259                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
15260                         return HANDLER_ERROR;
15261                 }
15262 -               
15263 +
15264                 if (i == 0 && buffer_is_empty(s->format)) {
15265                         /* set a default logfile string */
15266 -                       
15267 +
15268                         buffer_copy_string(s->format, "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"");
15269                 }
15270 -               
15271 +
15272                 /* parse */
15273 -               
15274 +
15275                 if (s->format->used) {
15276                         s->parsed_format = calloc(1, sizeof(*(s->parsed_format)));
15277 -                       
15278 +
15279                         if (-1 == accesslog_parse_format(srv, s->parsed_format, s->format)) {
15280  
15281 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
15282 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
15283                                                 "parsing accesslog-definition failed:", s->format);
15284  
15285                                 return HANDLER_ERROR;
15286                         }
15287  #if 0
15288 -                       /* debugging */                 
15289 +                       /* debugging */
15290                         for (j = 0; j < s->parsed_format->used; j++) {
15291                                 switch (s->parsed_format->ptr[j]->type) {
15292                                 case FIELD_FORMAT:
15293 -                                       log_error_write(srv, __FILE__, __LINE__, "ssds", 
15294 +                                       log_error_write(srv, __FILE__, __LINE__, "ssds",
15295                                                         "config:", "format", s->parsed_format->ptr[j]->field,
15296 -                                                       s->parsed_format->ptr[j]->string ? 
15297 +                                                       s->parsed_format->ptr[j]->string ?
15298                                                         s->parsed_format->ptr[j]->string->ptr : "" );
15299                                         break;
15300                                 case FIELD_STRING:
15301 @@ -446,52 +446,52 @@
15302                         }
15303  #endif
15304                 }
15305 -               
15306 +
15307                 if (s->use_syslog) {
15308                         /* ignore the next checks */
15309                         continue;
15310                 }
15311 -               
15312 +
15313                 if (buffer_is_empty(s->access_logfile)) continue;
15314 -               
15315 +
15316                 if (s->access_logfile->ptr[0] == '|') {
15317  #ifdef HAVE_FORK
15318                         /* create write pipe and spawn process */
15319 -                       
15320 +
15321                         int to_log_fds[2];
15322                         pid_t pid;
15323 -                       
15324 +
15325                         if (pipe(to_log_fds)) {
15326                                 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
15327                                 return HANDLER_ERROR;
15328                         }
15329 -                       
15330 +
15331                         /* fork, execve */
15332                         switch (pid = fork()) {
15333 -                       case 0: 
15334 +                       case 0:
15335                                 /* child */
15336 -                               
15337 +
15338                                 close(STDIN_FILENO);
15339                                 dup2(to_log_fds[0], STDIN_FILENO);
15340                                 close(to_log_fds[0]);
15341                                 /* not needed */
15342                                 close(to_log_fds[1]);
15343 -                               
15344 +
15345                                 /* we don't need the client socket */
15346                                 for (i = 3; i < 256; i++) {
15347                                         close(i);
15348                                 }
15349 -                               
15350 -                               /* exec the log-process (skip the | ) 
15351 -                                * 
15352 +
15353 +                               /* exec the log-process (skip the | )
15354 +                                *
15355                                  */
15356 -                               
15357 +
15358                                 execl("/bin/sh", "sh", "-c", s->access_logfile->ptr + 1, NULL);
15359  
15360 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
15361 -                                               "spawning log-process failed: ", strerror(errno), 
15362 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
15363 +                                               "spawning log-process failed: ", strerror(errno),
15364                                                 s->access_logfile->ptr + 1);
15365 -                               
15366 +
15367                                 exit(-1);
15368                                 break;
15369                         case -1:
15370 @@ -500,27 +500,28 @@
15371                                 break;
15372                         default:
15373                                 close(to_log_fds[0]);
15374 -                               
15375 +
15376                                 s->log_access_fd = to_log_fds[1];
15377 -                               
15378 +
15379                                 break;
15380                         }
15381  #else
15382                         return -1;
15383  #endif
15384 -               } else if (-1 == (s->log_access_fd = 
15385 +               } else if (-1 == (s->log_access_fd =
15386                                   open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
15387 -                       
15388 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", 
15389 -                                       "opening access-log failed:", 
15390 +
15391 +                       log_error_write(srv, __FILE__, __LINE__, "ssb",
15392 +                                       "opening access-log failed:",
15393                                         strerror(errno), s->access_logfile);
15394 -                       
15395 +
15396                         return HANDLER_ERROR;
15397                 }
15398 +#ifndef _WIN32
15399                 fcntl(s->log_access_fd, F_SETFD, FD_CLOEXEC);
15400 -       
15401 +#endif
15402         }
15403 -       
15404 +
15405         return HANDLER_GO_ON;
15406  }
15407  
15408 @@ -529,7 +530,7 @@
15409         size_t i;
15410  
15411         if (!p->config_storage) return HANDLER_GO_ON;
15412 -               
15413 +
15414         for (i = 0; i < srv->config_context->used; i++) {
15415                 plugin_config *s = p->config_storage[i];
15416  
15417 @@ -544,90 +545,87 @@
15418                         } else if (s->log_access_fd != -1) {
15419                                 write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
15420                         }
15421 -                       
15422 +
15423                         buffer_reset(s->access_logbuffer);
15424                 }
15425 -               
15426 +
15427                 if (s->use_syslog == 0 &&
15428                     !buffer_is_empty(s->access_logfile) &&
15429                     s->access_logfile->ptr[0] != '|') {
15430 -                       
15431 +
15432                         close(s->log_access_fd);
15433 -                       
15434 -                       if (-1 == (s->log_access_fd = 
15435 +
15436 +                       if (-1 == (s->log_access_fd =
15437                                    open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
15438 -                               
15439 +
15440                                 log_error_write(srv, __FILE__, __LINE__, "ss", "cycling access-log failed:", strerror(errno));
15441 -                               
15442 +
15443                                 return HANDLER_ERROR;
15444                         }
15445                 }
15446         }
15447 -       
15448 +
15449         return HANDLER_GO_ON;
15450  }
15451  
15452 -#define PATCH(x) \
15453 -       p->conf.x = s->x;
15454  static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_data *p) {
15455         size_t i, j;
15456         plugin_config *s = p->config_storage[0];
15457 -       
15458 -       PATCH(access_logfile);
15459 -       PATCH(format);
15460 -       PATCH(log_access_fd);
15461 -       PATCH(last_generated_accesslog_ts_ptr);
15462 -       PATCH(access_logbuffer);
15463 -       PATCH(ts_accesslog_str);
15464 -       PATCH(parsed_format);
15465 -       PATCH(use_syslog);
15466 -       
15467 +
15468 +       PATCH_OPTION(access_logfile);
15469 +       PATCH_OPTION(format);
15470 +       PATCH_OPTION(log_access_fd);
15471 +       PATCH_OPTION(last_generated_accesslog_ts_ptr);
15472 +       PATCH_OPTION(access_logbuffer);
15473 +       PATCH_OPTION(ts_accesslog_str);
15474 +       PATCH_OPTION(parsed_format);
15475 +       PATCH_OPTION(use_syslog);
15476 +
15477         /* skip the first, the global context */
15478         for (i = 1; i < srv->config_context->used; i++) {
15479                 data_config *dc = (data_config *)srv->config_context->data[i];
15480                 s = p->config_storage[i];
15481 -               
15482 +
15483                 /* condition didn't match */
15484                 if (!config_check_cond(srv, con, dc)) continue;
15485 -               
15486 +
15487                 /* merge config */
15488                 for (j = 0; j < dc->value->used; j++) {
15489                         data_unset *du = dc->value->data[j];
15490 -                       
15491 +
15492                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.filename"))) {
15493 -                               PATCH(access_logfile);
15494 -                               PATCH(log_access_fd);
15495 -                               PATCH(last_generated_accesslog_ts_ptr);
15496 -                               PATCH(access_logbuffer);
15497 -                               PATCH(ts_accesslog_str);
15498 +                               PATCH_OPTION(access_logfile);
15499 +                               PATCH_OPTION(log_access_fd);
15500 +                               PATCH_OPTION(last_generated_accesslog_ts_ptr);
15501 +                               PATCH_OPTION(access_logbuffer);
15502 +                               PATCH_OPTION(ts_accesslog_str);
15503                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.format"))) {
15504 -                               PATCH(format);
15505 -                               PATCH(parsed_format);
15506 +                               PATCH_OPTION(format);
15507 +                               PATCH_OPTION(parsed_format);
15508                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.use-syslog"))) {
15509 -                               PATCH(use_syslog);
15510 +                               PATCH_OPTION(use_syslog);
15511                         }
15512                 }
15513         }
15514 -       
15515 +
15516         return 0;
15517  }
15518 -#undef PATCH
15519  
15520  REQUESTDONE_FUNC(log_access_write) {
15521         plugin_data *p = p_d;
15522         buffer *b;
15523         size_t j;
15524 -       
15525 +
15526         int newts = 0;
15527         data_string *ds;
15528 -       
15529 +
15530         mod_accesslog_patch_connection(srv, con, p);
15531 -       
15532 +
15533         b = p->conf.access_logbuffer;
15534         if (b->used == 0) {
15535                 buffer_copy_string(b, "");
15536         }
15537 -       
15538 +
15539         for (j = 0; j < p->conf.parsed_format->used; j++) {
15540                 switch(p->conf.parsed_format->ptr[j]->type) {
15541                 case FIELD_STRING:
15542 @@ -636,14 +634,14 @@
15543                 case FIELD_FORMAT:
15544                         switch(p->conf.parsed_format->ptr[j]->field) {
15545                         case FORMAT_TIMESTAMP:
15546 -                               
15547 +
15548                                 /* cache the generated timestamp */
15549                                 if (srv->cur_ts != *(p->conf.last_generated_accesslog_ts_ptr)) {
15550                                         struct tm tm;
15551  #if defined(HAVE_STRUCT_TM_GMTOFF)
15552                                         long scd, hrs, min;
15553  #endif
15554 -               
15555 +
15556                                         buffer_prepare_copy(p->conf.ts_accesslog_str, 255);
15557  #if defined(HAVE_STRUCT_TM_GMTOFF)
15558  # ifdef HAVE_LOCALTIME_R
15559 @@ -653,17 +651,17 @@
15560                                         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)));
15561  # endif
15562                                         p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
15563 -                                       
15564 +
15565                                         buffer_append_string(p->conf.ts_accesslog_str, tm.tm_gmtoff >= 0 ? "+" : "-");
15566 -                                       
15567 +
15568                                         scd = abs(tm.tm_gmtoff);
15569                                         hrs = scd / 3600;
15570                                         min = (scd % 3600) / 60;
15571 -                                       
15572 +
15573                                         /* hours */
15574                                         if (hrs < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
15575                                         buffer_append_long(p->conf.ts_accesslog_str, hrs);
15576 -                                       
15577 +
15578                                         if (min < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
15579                                         buffer_append_long(p->conf.ts_accesslog_str, min);
15580                                         BUFFER_APPEND_STRING_CONST(p->conf.ts_accesslog_str, "]");
15581 @@ -676,20 +674,20 @@
15582  #endif
15583                                         p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
15584  #endif
15585 -                                       
15586 +
15587                                         *(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts;
15588                                         newts = 1;
15589                                 }
15590 -                               
15591 +
15592                                 buffer_append_string_buffer(b, p->conf.ts_accesslog_str);
15593 -                               
15594 +
15595                                 break;
15596                         case FORMAT_REMOTE_HOST:
15597 -       
15598 +
15599                                 /* handle inet_ntop cache */
15600 -       
15601 +
15602                                 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
15603 -                               
15604 +
15605                                 break;
15606                         case FORMAT_REMOTE_IDENT:
15607                                 /* ident */
15608 @@ -710,10 +708,10 @@
15609                         case FORMAT_STATUS:
15610                                 buffer_append_long(b, con->http_status);
15611                                 break;
15612 -       
15613 +
15614                         case FORMAT_BYTES_OUT_NO_HEADER:
15615                                 if (con->bytes_written > 0) {
15616 -                                       buffer_append_off_t(b, 
15617 +                                       buffer_append_off_t(b,
15618                                                             con->bytes_written - con->bytes_header <= 0 ? 0 : con->bytes_written - con->bytes_header);
15619                                 } else {
15620                                         BUFFER_APPEND_STRING_CONST(b, "-");
15621 @@ -772,7 +770,7 @@
15622                                 }
15623                                 break;
15624                         case FORMAT_REQUEST_PROTOCOL:
15625 -                               buffer_append_string(b, 
15626 +                               buffer_append_string(b,
15627                                                      con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0");
15628                                 break;
15629                         case FORMAT_REQUEST_METHOD:
15630 @@ -801,7 +799,7 @@
15631                                  { 'D', FORMAT_TIME_USED_MS },
15632                                  { 'e', FORMAT_ENV },
15633                                  */
15634 -                               
15635 +
15636                                 break;
15637                         }
15638                         break;
15639 @@ -809,7 +807,7 @@
15640                         break;
15641                 }
15642         }
15643 -       
15644 +
15645         BUFFER_APPEND_STRING_CONST(b, "\n");
15646  
15647         if (p->conf.use_syslog ||  /* syslog doesn't cache */
15648 @@ -828,7 +826,7 @@
15649                 }
15650                 buffer_reset(b);
15651         }
15652 -       
15653 +
15654         return HANDLER_GO_ON;
15655  }
15656  
15657 @@ -836,15 +834,15 @@
15658  int mod_accesslog_plugin_init(plugin *p) {
15659         p->version     = LIGHTTPD_VERSION_ID;
15660         p->name        = buffer_init_string("accesslog");
15661 -       
15662 +
15663         p->init        = mod_accesslog_init;
15664         p->set_defaults= log_access_open;
15665         p->cleanup     = mod_accesslog_free;
15666 -       
15667 +
15668         p->handle_request_done  = log_access_write;
15669         p->handle_sighup        = log_access_cycle;
15670 -       
15671 +
15672         p->data        = NULL;
15673 -       
15674 +
15675         return 0;
15676  }
15677 --- ../lighttpd-1.4.11/src/mod_alias.c  2006-03-01 23:18:51.000000000 +0200
15678 +++ lighttpd-1.4.12/src/mod_alias.c     2006-07-16 00:26:03.000000000 +0300
15679 @@ -8,6 +8,7 @@
15680  #include "buffer.h"
15681  
15682  #include "plugin.h"
15683 +#include "sys-strings.h"
15684  
15685  /* plugin config for all request/connections */
15686  typedef struct {
15687 @@ -16,44 +17,44 @@
15688  
15689  typedef struct {
15690         PLUGIN_DATA;
15691 -       
15692 +
15693         plugin_config **config_storage;
15694 -       
15695 -       plugin_config conf; 
15696 +
15697 +       plugin_config conf;
15698  } plugin_data;
15699  
15700  /* init the plugin data */
15701  INIT_FUNC(mod_alias_init) {
15702         plugin_data *p;
15703 -       
15704 +
15705         p = calloc(1, sizeof(*p));
15706 -       
15707 -       
15708 -       
15709 +
15710 +
15711 +
15712         return p;
15713  }
15714  
15715  /* detroy the plugin data */
15716  FREE_FUNC(mod_alias_free) {
15717         plugin_data *p = p_d;
15718 -       
15719 +
15720         if (!p) return HANDLER_GO_ON;
15721 -       
15722 +
15723         if (p->config_storage) {
15724                 size_t i;
15725 -               
15726 +
15727                 for (i = 0; i < srv->config_context->used; i++) {
15728                         plugin_config *s = p->config_storage[i];
15729 -                       
15730 +
15731                         array_free(s->alias);
15732 -                       
15733 +
15734                         free(s);
15735                 }
15736                 free(p->config_storage);
15737         }
15738 -       
15739 +
15740         free(p);
15741 -       
15742 +
15743         return HANDLER_GO_ON;
15744  }
15745  
15746 @@ -62,25 +63,25 @@
15747  SETDEFAULTS_FUNC(mod_alias_set_defaults) {
15748         plugin_data *p = p_d;
15749         size_t i = 0;
15750 -       
15751 -       config_values_t cv[] = { 
15752 +
15753 +       config_values_t cv[] = {
15754                 { "alias.url",                  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
15755                 { NULL,                         NULL, T_CONFIG_UNSET,  T_CONFIG_SCOPE_UNSET }
15756         };
15757 -       
15758 +
15759         if (!p) return HANDLER_ERROR;
15760 -       
15761 +
15762         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
15763 -       
15764 +
15765         for (i = 0; i < srv->config_context->used; i++) {
15766                 plugin_config *s;
15767 -               
15768 +
15769                 s = calloc(1, sizeof(plugin_config));
15770 -               s->alias = array_init();        
15771 +               s->alias = array_init();
15772                 cv[0].destination = s->alias;
15773 -               
15774 +
15775                 p->config_storage[i] = s;
15776 -               
15777 +
15778                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
15779                         return HANDLER_ERROR;
15780                 }
15781 @@ -110,76 +111,73 @@
15782                         }
15783                 }
15784         }
15785 -       
15786 +
15787         return HANDLER_GO_ON;
15788  }
15789  
15790 -#define PATCH(x) \
15791 -       p->conf.x = s->x;
15792  static int mod_alias_patch_connection(server *srv, connection *con, plugin_data *p) {
15793         size_t i, j;
15794         plugin_config *s = p->config_storage[0];
15795 -       
15796 -       PATCH(alias);
15797 -       
15798 +
15799 +       PATCH_OPTION(alias);
15800 +
15801         /* skip the first, the global context */
15802         for (i = 1; i < srv->config_context->used; i++) {
15803                 data_config *dc = (data_config *)srv->config_context->data[i];
15804                 s = p->config_storage[i];
15805 -               
15806 +
15807                 /* condition didn't match */
15808                 if (!config_check_cond(srv, con, dc)) continue;
15809 -               
15810 +
15811                 /* merge config */
15812                 for (j = 0; j < dc->value->used; j++) {
15813                         data_unset *du = dc->value->data[j];
15814 -                       
15815 +
15816                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("alias.url"))) {
15817 -                               PATCH(alias);
15818 +                               PATCH_OPTION(alias);
15819                         }
15820                 }
15821         }
15822 -       
15823 +
15824         return 0;
15825  }
15826 -#undef PATCH
15827  
15828  PHYSICALPATH_FUNC(mod_alias_physical_handler) {
15829         plugin_data *p = p_d;
15830         int uri_len, basedir_len;
15831         char *uri_ptr;
15832         size_t k;
15833 -       
15834 +
15835         if (con->physical.path->used == 0) return HANDLER_GO_ON;
15836 -       
15837 +
15838         mod_alias_patch_connection(srv, con, p);
15839 -       
15840 +
15841         /* not to include the tailing slash */
15842         basedir_len = (con->physical.basedir->used - 1) - 1;
15843         uri_len = con->physical.path->used - 1 - basedir_len;
15844         uri_ptr = con->physical.path->ptr + basedir_len;
15845 -       
15846 +
15847         for (k = 0; k < p->conf.alias->used; k++) {
15848                 data_string *ds = (data_string *)p->conf.alias->data[k];
15849                 int alias_len = ds->key->used - 1;
15850 -               
15851 +
15852                 if (alias_len > uri_len) continue;
15853                 if (ds->key->used == 0) continue;
15854 -               
15855 +
15856                 if (0 == (con->conf.force_lowercase_filenames ?
15857                                         strncasecmp(uri_ptr, ds->key->ptr, alias_len) :
15858                                         strncmp(uri_ptr, ds->key->ptr, alias_len))) {
15859                         /* matched */
15860 -                       
15861 +
15862                         buffer_copy_string_buffer(con->physical.basedir, ds->value);
15863                         buffer_copy_string_buffer(srv->tmp_buf, ds->value);
15864                         buffer_append_string(srv->tmp_buf, uri_ptr + alias_len);
15865                         buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
15866 -                       
15867 +
15868                         return HANDLER_GO_ON;
15869                 }
15870         }
15871 -       
15872 +
15873         /* not found */
15874         return HANDLER_GO_ON;
15875  }
15876 @@ -189,13 +187,13 @@
15877  int mod_alias_plugin_init(plugin *p) {
15878         p->version     = LIGHTTPD_VERSION_ID;
15879         p->name        = buffer_init_string("alias");
15880 -       
15881 +
15882         p->init           = mod_alias_init;
15883         p->handle_physical= mod_alias_physical_handler;
15884         p->set_defaults   = mod_alias_set_defaults;
15885         p->cleanup        = mod_alias_free;
15886 -       
15887 +
15888         p->data        = NULL;
15889 -       
15890 +
15891         return 0;
15892  }
15893 --- ../lighttpd-1.4.11/src/mod_auth.c   2006-02-15 20:01:31.000000000 +0200
15894 +++ lighttpd-1.4.12/src/mod_auth.c      2006-07-18 13:03:40.000000000 +0300
15895 @@ -5,168 +5,167 @@
15896  #include <string.h>
15897  #include <errno.h>
15898  #include <fcntl.h>
15899 -#include <unistd.h>
15900  
15901  #include "plugin.h"
15902  #include "http_auth.h"
15903  #include "log.h"
15904  #include "response.h"
15905  
15906 +#include "sys-strings.h"
15907 +#include "sys-files.h"
15908 +
15909  handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
15910  
15911  
15912  /**
15913   * the basic and digest auth framework
15914 - * 
15915 + *
15916   * - config handling
15917   * - protocol handling
15918 - * 
15919 - * http_auth.c 
15920 - * http_auth_digest.c 
15921 - * 
15922 + *
15923 + * http_auth.c
15924 + * http_auth_digest.c
15925 + *
15926   * do the real work
15927   */
15928  
15929  INIT_FUNC(mod_auth_init) {
15930         mod_auth_plugin_data *p;
15931 -       
15932 +
15933         p = calloc(1, sizeof(*p));
15934 -       
15935 +
15936         p->tmp_buf = buffer_init();
15937 -       
15938 +
15939         p->auth_user = buffer_init();
15940  #ifdef USE_LDAP
15941         p->ldap_filter = buffer_init();
15942  #endif
15943 -       
15944 +
15945         return p;
15946  }
15947  
15948  FREE_FUNC(mod_auth_free) {
15949         mod_auth_plugin_data *p = p_d;
15950 -       
15951 +
15952         UNUSED(srv);
15953  
15954         if (!p) return HANDLER_GO_ON;
15955 -       
15956 +
15957         buffer_free(p->tmp_buf);
15958         buffer_free(p->auth_user);
15959  #ifdef USE_LDAP
15960         buffer_free(p->ldap_filter);
15961  #endif
15962 -       
15963 +
15964         if (p->config_storage) {
15965                 size_t i;
15966                 for (i = 0; i < srv->config_context->used; i++) {
15967                         mod_auth_plugin_config *s = p->config_storage[i];
15968 -                       
15969 +
15970                         if (!s) continue;
15971 -                       
15972 +
15973                         array_free(s->auth_require);
15974                         buffer_free(s->auth_plain_groupfile);
15975                         buffer_free(s->auth_plain_userfile);
15976                         buffer_free(s->auth_htdigest_userfile);
15977                         buffer_free(s->auth_htpasswd_userfile);
15978                         buffer_free(s->auth_backend_conf);
15979 -                       
15980 +
15981                         buffer_free(s->auth_ldap_hostname);
15982                         buffer_free(s->auth_ldap_basedn);
15983                         buffer_free(s->auth_ldap_binddn);
15984                         buffer_free(s->auth_ldap_bindpw);
15985                         buffer_free(s->auth_ldap_filter);
15986                         buffer_free(s->auth_ldap_cafile);
15987 -                       
15988 +
15989  #ifdef USE_LDAP
15990                         buffer_free(s->ldap_filter_pre);
15991                         buffer_free(s->ldap_filter_post);
15992 -                       
15993 +
15994                         if (s->ldap) ldap_unbind_s(s->ldap);
15995  #endif
15996 -                       
15997 +
15998                         free(s);
15999                 }
16000                 free(p->config_storage);
16001         }
16002 -       
16003 +
16004         free(p);
16005 -       
16006 +
16007         return HANDLER_GO_ON;
16008  }
16009  
16010 -#define PATCH(x) \
16011 -       p->conf.x = s->x;
16012  static int mod_auth_patch_connection(server *srv, connection *con, mod_auth_plugin_data *p) {
16013         size_t i, j;
16014         mod_auth_plugin_config *s = p->config_storage[0];
16015  
16016 -       PATCH(auth_backend);
16017 -       PATCH(auth_plain_groupfile);
16018 -       PATCH(auth_plain_userfile);
16019 -       PATCH(auth_htdigest_userfile);
16020 -       PATCH(auth_htpasswd_userfile);
16021 -       PATCH(auth_require);
16022 -       PATCH(auth_debug);
16023 -       PATCH(auth_ldap_hostname);
16024 -       PATCH(auth_ldap_basedn);
16025 -       PATCH(auth_ldap_binddn);
16026 -       PATCH(auth_ldap_bindpw);
16027 -       PATCH(auth_ldap_filter);
16028 -       PATCH(auth_ldap_cafile);
16029 -       PATCH(auth_ldap_starttls);
16030 +       PATCH_OPTION(auth_backend);
16031 +       PATCH_OPTION(auth_plain_groupfile);
16032 +       PATCH_OPTION(auth_plain_userfile);
16033 +       PATCH_OPTION(auth_htdigest_userfile);
16034 +       PATCH_OPTION(auth_htpasswd_userfile);
16035 +       PATCH_OPTION(auth_require);
16036 +       PATCH_OPTION(auth_debug);
16037 +       PATCH_OPTION(auth_ldap_hostname);
16038 +       PATCH_OPTION(auth_ldap_basedn);
16039 +       PATCH_OPTION(auth_ldap_binddn);
16040 +       PATCH_OPTION(auth_ldap_bindpw);
16041 +       PATCH_OPTION(auth_ldap_filter);
16042 +       PATCH_OPTION(auth_ldap_cafile);
16043 +       PATCH_OPTION(auth_ldap_starttls);
16044  #ifdef USE_LDAP
16045 -       PATCH(ldap);
16046 -       PATCH(ldap_filter_pre);
16047 -       PATCH(ldap_filter_post);
16048 +       PATCH_OPTION(ldap);
16049 +       PATCH_OPTION(ldap_filter_pre);
16050 +       PATCH_OPTION(ldap_filter_post);
16051  #endif
16052 -       
16053 +
16054         /* skip the first, the global context */
16055         for (i = 1; i < srv->config_context->used; i++) {
16056                 data_config *dc = (data_config *)srv->config_context->data[i];
16057                 s = p->config_storage[i];
16058 -               
16059 +
16060                 /* condition didn't match */
16061                 if (!config_check_cond(srv, con, dc)) continue;
16062 -               
16063 +
16064                 /* merge config */
16065                 for (j = 0; j < dc->value->used; j++) {
16066                         data_unset *du = dc->value->data[j];
16067 -                       
16068 +
16069                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend"))) {
16070 -                               PATCH(auth_backend);
16071 +                               PATCH_OPTION(auth_backend);
16072                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.groupfile"))) {
16073 -                               PATCH(auth_plain_groupfile);
16074 +                               PATCH_OPTION(auth_plain_groupfile);
16075                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.userfile"))) {
16076 -                               PATCH(auth_plain_userfile);
16077 +                               PATCH_OPTION(auth_plain_userfile);
16078                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htdigest.userfile"))) {
16079 -                               PATCH(auth_htdigest_userfile);
16080 +                               PATCH_OPTION(auth_htdigest_userfile);
16081                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htpasswd.userfile"))) {
16082 -                               PATCH(auth_htpasswd_userfile);
16083 +                               PATCH_OPTION(auth_htpasswd_userfile);
16084                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.require"))) {
16085 -                               PATCH(auth_require);
16086 +                               PATCH_OPTION(auth_require);
16087                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.debug"))) {
16088 -                               PATCH(auth_debug);
16089 +                               PATCH_OPTION(auth_debug);
16090                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.hostname"))) {
16091 -                               PATCH(auth_ldap_hostname);
16092 +                               PATCH_OPTION(auth_ldap_hostname);
16093  #ifdef USE_LDAP
16094 -                               PATCH(ldap);
16095 -                               PATCH(ldap_filter_pre);
16096 -                               PATCH(ldap_filter_post);
16097 +                               PATCH_OPTION(ldap);
16098 +                               PATCH_OPTION(ldap_filter_pre);
16099 +                               PATCH_OPTION(ldap_filter_post);
16100  #endif
16101                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.base-dn"))) {
16102 -                               PATCH(auth_ldap_basedn);
16103 +                               PATCH_OPTION(auth_ldap_basedn);
16104                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) {
16105 -                               PATCH(auth_ldap_filter);
16106 +                               PATCH_OPTION(auth_ldap_filter);
16107                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.ca-file"))) {
16108 -                               PATCH(auth_ldap_cafile);
16109 +                               PATCH_OPTION(auth_ldap_cafile);
16110                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.starttls"))) {
16111 -                               PATCH(auth_ldap_starttls);
16112 +                               PATCH_OPTION(auth_ldap_starttls);
16113                         }
16114                 }
16115         }
16116 -       
16117 +
16118         return 0;
16119  }
16120 -#undef PATCH
16121  
16122  static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
16123         size_t k;
16124 @@ -175,22 +174,22 @@
16125         data_string *ds;
16126         mod_auth_plugin_data *p = p_d;
16127         array *req;
16128 -       
16129 +
16130         /* select the right config */
16131         mod_auth_patch_connection(srv, con, p);
16132 -       
16133 +
16134         if (p->conf.auth_require == NULL) return HANDLER_GO_ON;
16135 -       
16136 +
16137         /*
16138          * AUTH
16139 -        *  
16140 +        *
16141          */
16142 -       
16143 +
16144         /* do we have to ask for auth ? */
16145 -       
16146 +
16147         auth_required = 0;
16148         auth_satisfied = 0;
16149 -       
16150 +
16151         /* search auth-directives for path */
16152         for (k = 0; k < p->conf.auth_require->used; k++) {
16153                 buffer *req = p->conf.auth_require->data[k]->key;
16154 @@ -212,76 +211,76 @@
16155                         }
16156                 }
16157         }
16158 -       
16159 +
16160         /* nothing to do for us */
16161         if (auth_required == 0) return HANDLER_GO_ON;
16162 -       
16163 +
16164         req = ((data_array *)(p->conf.auth_require->data[k]))->value;
16165 -       
16166 +
16167         /* try to get Authorization-header */
16168 -               
16169 +
16170         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization"))) {
16171                 http_authorization = ds->value->ptr;
16172         }
16173 -       
16174 +
16175         if (ds && ds->value && ds->value->used) {
16176                 char *auth_realm;
16177                 data_string *method;
16178 -               
16179 +
16180                 method = (data_string *)array_get_element(req, "method");
16181 -               
16182 +
16183                 /* parse auth-header */
16184                 if (NULL != (auth_realm = strchr(http_authorization, ' '))) {
16185                         int auth_type_len = auth_realm - http_authorization;
16186 -                       
16187 +
16188                         if ((auth_type_len == 5) &&
16189                             (0 == strncmp(http_authorization, "Basic", auth_type_len))) {
16190 -                               
16191 -                               if (0 == strcmp(method->value->ptr, "basic")) {
16192 +
16193 +                               if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
16194                                         auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1);
16195                                 }
16196                         } else if ((auth_type_len == 6) &&
16197                                    (0 == strncmp(http_authorization, "Digest", auth_type_len))) {
16198 -                               if (0 == strcmp(method->value->ptr, "digest")) {
16199 +                               if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
16200                                         if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) {
16201                                                 con->http_status = 400;
16202 -                                               
16203 +
16204                                                 /* a field was missing */
16205 -                                               
16206 +
16207                                                 return HANDLER_FINISHED;
16208                                         }
16209                                 }
16210                         } else {
16211 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16212 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16213                                                 "unknown authentification type:",
16214                                                 http_authorization);
16215                         }
16216                 }
16217         }
16218 -       
16219 +
16220         if (!auth_satisfied) {
16221                 data_string *method, *realm;
16222                 method = (data_string *)array_get_element(req, "method");
16223                 realm = (data_string *)array_get_element(req, "realm");
16224 -               
16225 +
16226                 con->http_status = 401;
16227 -                       
16228 -               if (0 == strcmp(method->value->ptr, "basic")) {
16229 +
16230 +               if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
16231                         buffer_copy_string(p->tmp_buf, "Basic realm=\"");
16232                         buffer_append_string_buffer(p->tmp_buf, realm->value);
16233                         buffer_append_string(p->tmp_buf, "\"");
16234 -                       
16235 +
16236                         response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
16237 -               } else if (0 == strcmp(method->value->ptr, "digest")) {
16238 +               } else if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
16239                         char hh[33];
16240                         http_auth_digest_generate_nonce(srv, p, srv->tmp_buf, hh);
16241 -                       
16242 +
16243                         buffer_copy_string(p->tmp_buf, "Digest realm=\"");
16244                         buffer_append_string_buffer(p->tmp_buf, realm->value);
16245                         buffer_append_string(p->tmp_buf, "\", nonce=\"");
16246                         buffer_append_string(p->tmp_buf, hh);
16247                         buffer_append_string(p->tmp_buf, "\", qop=\"auth\"");
16248 -                       
16249 +
16250                         response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
16251                 } else {
16252                         /* evil */
16253 @@ -289,18 +288,18 @@
16254                 return HANDLER_FINISHED;
16255         } else {
16256                 /* the REMOTE_USER header */
16257 -               
16258 +
16259                 buffer_copy_string_buffer(con->authed_user, p->auth_user);
16260         }
16261 -       
16262 +
16263         return HANDLER_GO_ON;
16264  }
16265  
16266  SETDEFAULTS_FUNC(mod_auth_set_defaults) {
16267         mod_auth_plugin_data *p = p_d;
16268         size_t i;
16269 -       
16270 -       config_values_t cv[] = { 
16271 +
16272 +       config_values_t cv[] = {
16273                 { "auth.backend",                   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
16274                 { "auth.backend.plain.groupfile",   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
16275                 { "auth.backend.plain.userfile",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
16276 @@ -317,7 +316,7 @@
16277                 { "auth.debug",                     NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },  /* 13 */
16278                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
16279         };
16280 -       
16281 +
16282         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
16283  
16284         for (i = 0; i < srv->config_context->used; i++) {
16285 @@ -325,14 +324,14 @@
16286                 size_t n;
16287                 data_array *da;
16288                 array *ca;
16289 -               
16290 +
16291                 s = calloc(1, sizeof(mod_auth_plugin_config));
16292                 s->auth_plain_groupfile = buffer_init();
16293                 s->auth_plain_userfile = buffer_init();
16294                 s->auth_htdigest_userfile = buffer_init();
16295                 s->auth_htpasswd_userfile = buffer_init();
16296                 s->auth_backend_conf = buffer_init();
16297 -               
16298 +
16299                 s->auth_ldap_hostname = buffer_init();
16300                 s->auth_ldap_basedn = buffer_init();
16301                 s->auth_ldap_binddn = buffer_init();
16302 @@ -341,15 +340,15 @@
16303                 s->auth_ldap_cafile = buffer_init();
16304                 s->auth_ldap_starttls = 0;
16305                 s->auth_debug = 0;
16306 -               
16307 +
16308                 s->auth_require = array_init();
16309 -               
16310 +
16311  #ifdef USE_LDAP
16312                 s->ldap_filter_pre = buffer_init();
16313                 s->ldap_filter_post = buffer_init();
16314                 s->ldap = NULL;
16315  #endif
16316 -       
16317 +
16318                 cv[0].destination = s->auth_backend_conf;
16319                 cv[1].destination = s->auth_plain_groupfile;
16320                 cv[2].destination = s->auth_plain_userfile;
16321 @@ -364,146 +363,148 @@
16322                 cv[11].destination = s->auth_htdigest_userfile;
16323                 cv[12].destination = s->auth_htpasswd_userfile;
16324                 cv[13].destination = &(s->auth_debug);
16325 -               
16326 +
16327                 p->config_storage[i] = s;
16328                 ca = ((data_config *)srv->config_context->data[i])->value;
16329 -               
16330 +
16331                 if (0 != config_insert_values_global(srv, ca, cv)) {
16332                         return HANDLER_ERROR;
16333                 }
16334 -               
16335 -               if (s->auth_backend_conf->used) {
16336 -                       if (0 == strcmp(s->auth_backend_conf->ptr, "htpasswd")) {
16337 +
16338 +               if (!buffer_is_empty(s->auth_backend_conf)) {
16339 +                       if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htpasswd"))) {
16340                                 s->auth_backend = AUTH_BACKEND_HTPASSWD;
16341 -                       } else if (0 == strcmp(s->auth_backend_conf->ptr, "htdigest")) {
16342 +                       } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htdigest"))) {
16343                                 s->auth_backend = AUTH_BACKEND_HTDIGEST;
16344 -                       } else if (0 == strcmp(s->auth_backend_conf->ptr, "plain")) {
16345 +                       } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("plain"))) {
16346                                 s->auth_backend = AUTH_BACKEND_PLAIN;
16347 -                       } else if (0 == strcmp(s->auth_backend_conf->ptr, "ldap")) {
16348 +                       } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("ldap"))) {
16349                                 s->auth_backend = AUTH_BACKEND_LDAP;
16350                         } else {
16351                                 log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf);
16352 -                               
16353 +
16354                                 return HANDLER_ERROR;
16355                         }
16356                 }
16357  
16358                 /* no auth.require for this section */
16359                 if (NULL == (da = (data_array *)array_get_element(ca, "auth.require"))) continue;
16360 -               
16361 +
16362                 if (da->type != TYPE_ARRAY) continue;
16363 -               
16364 +
16365                 for (n = 0; n < da->value->used; n++) {
16366                         size_t m;
16367                         data_array *da_file = (data_array *)da->value->data[n];
16368 -                       const char *method, *realm, *require;
16369 -                       
16370 +                       buffer *method, *realm, *require;
16371 +
16372                         if (da->value->data[n]->type != TYPE_ARRAY) {
16373 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16374 -                                               "auth.require should contain an array as in:", 
16375 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16376 +                                               "auth.require should contain an array as in:",
16377                                                 "auth.require = ( \"...\" => ( ..., ...) )");
16378  
16379                                 return HANDLER_ERROR;
16380                         }
16381 -                                       
16382 +
16383                         method = realm = require = NULL;
16384 -                                       
16385 +
16386                         for (m = 0; m < da_file->value->used; m++) {
16387 -                               if (da_file->value->data[m]->type == TYPE_STRING) {
16388 -                                       if (0 == strcmp(da_file->value->data[m]->key->ptr, "method")) {
16389 -                                               method = ((data_string *)(da_file->value->data[m]))->value->ptr;
16390 -                                       } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "realm")) {
16391 -                                               realm = ((data_string *)(da_file->value->data[m]))->value->ptr;
16392 -                                       } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "require")) {
16393 -                                               require = ((data_string *)(da_file->value->data[m]))->value->ptr;
16394 -                                       } else {
16395 -                                               log_error_write(srv, __FILE__, __LINE__, "ssbs", 
16396 -                                                       "the field is unknown in:", 
16397 +                               data_string *ds_auth_req = (data_string *)da_file->value->data[m];
16398 +
16399 +                               if (ds_auth_req->type != TYPE_STRING) {
16400 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbs",
16401 +                                               "a string was expected for:",
16402 +                                               "auth.require = ( \"...\" => ( ..., -> \"",
16403 +                                               ds_auth_req->key,
16404 +                                               "\" <- => \"...\" ) )");
16405 +
16406 +                                       return HANDLER_ERROR;
16407 +                               }
16408 +
16409 +                               if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("method"))) {
16410 +                                       method = ds_auth_req->value;
16411 +                               } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("realm"))) {
16412 +                                       realm = ds_auth_req->value;
16413 +                               } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("require"))) {
16414 +                                       require = ds_auth_req->value;
16415 +                               } else {
16416 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbs",
16417 +                                                       "the field is unknown in:",
16418                                                         "auth.require = ( \"...\" => ( ..., -> \"",
16419                                                         da_file->value->data[m]->key,
16420                                                         "\" <- => \"...\" ) )");
16421  
16422 -                                               return HANDLER_ERROR;
16423 -                                       }
16424 -                               } else {
16425 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbs", 
16426 -                                               "a string was expected for:", 
16427 -                                               "auth.require = ( \"...\" => ( ..., -> \"",
16428 -                                               da_file->value->data[m]->key,
16429 -                                               "\" <- => \"...\" ) )");
16430 -                                       
16431                                         return HANDLER_ERROR;
16432 +
16433                                 }
16434                         }
16435 -                                       
16436 +
16437                         if (method == NULL) {
16438 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16439 -                                               "the require field is missing in:", 
16440 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16441 +                                               "the require field is missing in:",
16442                                                 "auth.require = ( \"...\" => ( ..., \"method\" => \"...\" ) )");
16443                                 return HANDLER_ERROR;
16444 -                       } else {
16445 -                               if (0 != strcmp(method, "basic") &&
16446 -                                   0 != strcmp(method, "digest")) {
16447 -                                       log_error_write(srv, __FILE__, __LINE__, "ss",
16448 -                                                       "method has to be either \"basic\" or \"digest\" in",
16449 -                                                       "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
16450 -                                       return HANDLER_ERROR;
16451 -                               }
16452 +                       } 
16453 +                       if (!buffer_is_equal_string(method, CONST_STR_LEN("basic")) &&
16454 +                           !buffer_is_equal_string(method, CONST_STR_LEN("digest"))) {
16455 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16456 +                                               "method has to be either \"basic\" or \"digest\" in",
16457 +                                               "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
16458 +                               return HANDLER_ERROR;
16459                         }
16460 -                       
16461 +
16462                         if (realm == NULL) {
16463 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16464 -                                               "the require field is missing in:", 
16465 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16466 +                                               "the require field is missing in:",
16467                                                 "auth.require = ( \"...\" => ( ..., \"realm\" => \"...\" ) )");
16468                                 return HANDLER_ERROR;
16469                         }
16470 -                       
16471 +
16472                         if (require == NULL) {
16473 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16474 -                                               "the require field is missing in:", 
16475 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16476 +                                               "the require field is missing in:",
16477                                                 "auth.require = ( \"...\" => ( ..., \"require\" => \"...\" ) )");
16478                                 return HANDLER_ERROR;
16479                         }
16480 -                       
16481 +
16482                         if (method && realm && require) {
16483                                 data_string *ds;
16484                                 data_array *a;
16485 -                               
16486 +
16487                                 a = data_array_init();
16488                                 buffer_copy_string_buffer(a->key, da_file->key);
16489 -                               
16490 +
16491                                 ds = data_string_init();
16492 -                               
16493 +
16494                                 buffer_copy_string(ds->key, "method");
16495 -                               buffer_copy_string(ds->value, method);
16496 -                               
16497 +                               buffer_copy_string_buffer(ds->value, method);
16498 +
16499                                 array_insert_unique(a->value, (data_unset *)ds);
16500 -                               
16501 +
16502                                 ds = data_string_init();
16503 -                               
16504 +
16505                                 buffer_copy_string(ds->key, "realm");
16506 -                               buffer_copy_string(ds->value, realm);
16507 -                               
16508 +                               buffer_copy_string_buffer(ds->value, realm);
16509 +
16510                                 array_insert_unique(a->value, (data_unset *)ds);
16511 -                               
16512 +
16513                                 ds = data_string_init();
16514 -                               
16515 +
16516                                 buffer_copy_string(ds->key, "require");
16517 -                               buffer_copy_string(ds->value, require);
16518 -                               
16519 +                               buffer_copy_string_buffer(ds->value, require);
16520 +
16521                                 array_insert_unique(a->value, (data_unset *)ds);
16522 -                               
16523 +
16524                                 array_insert_unique(s->auth_require, (data_unset *)a);
16525                         }
16526                 }
16527 -       
16528 +
16529                 switch(s->auth_backend) {
16530                 case AUTH_BACKEND_PLAIN:
16531                         if (s->auth_plain_userfile->used) {
16532                                 int fd;
16533                                 /* try to read */
16534                                 if (-1 == (fd = open(s->auth_plain_userfile->ptr, O_RDONLY))) {
16535 -                                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
16536 +                                       log_error_write(srv, __FILE__, __LINE__, "sbss",
16537                                                         "opening auth.backend.plain.userfile:", s->auth_plain_userfile,
16538                                                         "failed:", strerror(errno));
16539                                         return HANDLER_ERROR;
16540 @@ -516,7 +517,7 @@
16541                                 int fd;
16542                                 /* try to read */
16543                                 if (-1 == (fd = open(s->auth_htpasswd_userfile->ptr, O_RDONLY))) {
16544 -                                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
16545 +                                       log_error_write(srv, __FILE__, __LINE__, "sbss",
16546                                                         "opening auth.backend.htpasswd.userfile:", s->auth_htpasswd_userfile,
16547                                                         "failed:", strerror(errno));
16548                                         return HANDLER_ERROR;
16549 @@ -529,7 +530,7 @@
16550                                 int fd;
16551                                 /* try to read */
16552                                 if (-1 == (fd = open(s->auth_htdigest_userfile->ptr, O_RDONLY))) {
16553 -                                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
16554 +                                       log_error_write(srv, __FILE__, __LINE__, "sbss",
16555                                                         "opening auth.backend.htdigest.userfile:", s->auth_htdigest_userfile,
16556                                                         "failed:", strerror(errno));
16557                                         return HANDLER_ERROR;
16558 @@ -554,75 +555,75 @@
16559  handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s) {
16560  #ifdef USE_LDAP
16561                         int ret;
16562 -#if 0                  
16563 +#if 0
16564                         if (s->auth_ldap_basedn->used == 0) {
16565                                 log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.base-dn has to be set");
16566 -                               
16567 +
16568                                 return HANDLER_ERROR;
16569                         }
16570  #endif
16571 -                       
16572 +
16573                         if (s->auth_ldap_filter->used) {
16574                                 char *dollar;
16575 -                               
16576 +
16577                                 /* parse filter */
16578 -                       
16579 +
16580                                 if (NULL == (dollar = strchr(s->auth_ldap_filter->ptr, '$'))) {
16581                                         log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '$'");
16582 -                                       
16583 +
16584                                         return HANDLER_ERROR;
16585                                 }
16586 -                               
16587 +
16588                                 buffer_copy_string_len(s->ldap_filter_pre, s->auth_ldap_filter->ptr, dollar - s->auth_ldap_filter->ptr);
16589                                 buffer_copy_string(s->ldap_filter_post, dollar+1);
16590                         }
16591 -                       
16592 +
16593                         if (s->auth_ldap_hostname->used) {
16594                                 if (NULL == (s->ldap = ldap_init(s->auth_ldap_hostname->ptr, LDAP_PORT))) {
16595                                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
16596 -                                       
16597 +
16598                                         return HANDLER_ERROR;
16599                                 }
16600 -                               
16601 +
16602                                 ret = LDAP_VERSION3;
16603                                 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(s->ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
16604                                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16605 -                               
16606 +
16607                                         return HANDLER_ERROR;
16608                                 }
16609  
16610                                 if (s->auth_ldap_starttls) {
16611 -                                       /* if no CA file is given, it is ok, as we will use encryption 
16612 +                                       /* if no CA file is given, it is ok, as we will use encryption
16613                                          * if the server requires a CAfile it will tell us */
16614                                         if (!buffer_is_empty(s->auth_ldap_cafile)) {
16615 -                                               if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, 
16616 +                                               if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
16617                                                                                 s->auth_ldap_cafile->ptr))) {
16618 -                                                       log_error_write(srv, __FILE__, __LINE__, "ss", 
16619 +                                                       log_error_write(srv, __FILE__, __LINE__, "ss",
16620                                                                         "Loading CA certificate failed:", ldap_err2string(ret));
16621 -                                               
16622 +
16623                                                         return HANDLER_ERROR;
16624                                                 }
16625                                         }
16626 -       
16627 +
16628                                         if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(s->ldap, NULL,  NULL))) {
16629                                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
16630 -                                               
16631 +
16632                                                 return HANDLER_ERROR;
16633                                         }
16634                                 }
16635 -                               
16636 -                               
16637 +
16638 +
16639                                 /* 1. */
16640                                 if (s->auth_ldap_binddn->used) {
16641                                         if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, s->auth_ldap_binddn->ptr, s->auth_ldap_bindpw->ptr))) {
16642                                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16643 -                                               
16644 +
16645                                                 return HANDLER_ERROR;
16646                                         }
16647                                 } else {
16648                                         if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, NULL, NULL))) {
16649                                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16650 -                                               
16651 +
16652                                                 return HANDLER_ERROR;
16653                                         }
16654                                 }
16655 @@ -641,8 +642,8 @@
16656         p->set_defaults = mod_auth_set_defaults;
16657         p->handle_uri_clean = mod_auth_uri_handler;
16658         p->cleanup     = mod_auth_free;
16659 -       
16660 +
16661         p->data        = NULL;
16662 -       
16663 +
16664         return 0;
16665  }
16666 --- ../lighttpd-1.4.11/src/mod_cgi.c    2006-02-22 15:15:10.000000000 +0200
16667 +++ lighttpd-1.4.12/src/mod_cgi.c       2006-07-18 17:34:32.000000000 +0300
16668 @@ -1,21 +1,8 @@
16669  #include <sys/types.h>
16670 -#ifdef __WIN32
16671 -#include <winsock2.h>
16672 -#else
16673 -#include <sys/socket.h>
16674 -#include <sys/wait.h>
16675 -#include <sys/mman.h>
16676 -
16677 -#include <netinet/in.h>
16678 -
16679 -#include <arpa/inet.h>
16680 -#endif
16681  
16682 -#include <unistd.h>
16683  #include <errno.h>
16684  #include <stdlib.h>
16685  #include <string.h>
16686 -#include <fdevent.h>
16687  #include <signal.h>
16688  #include <ctype.h>
16689  #include <assert.h>
16690 @@ -29,8 +16,16 @@
16691  #include "connections.h"
16692  #include "joblist.h"
16693  #include "http_chunk.h"
16694 +#include "fdevent.h"
16695  
16696  #include "plugin.h"
16697 +#include "http_resp.h"
16698 +
16699 +#include "sys-files.h"
16700 +#include "sys-mmap.h"
16701 +#include "sys-socket.h"
16702 +#include "sys-strings.h"
16703 +#include "sys-process.h"
16704  
16705  #ifdef HAVE_SYS_FILIO_H
16706  # include <sys/filio.h>
16707 @@ -40,11 +35,12 @@
16708  
16709  typedef struct {
16710         char **ptr;
16711 -       
16712 +
16713         size_t size;
16714         size_t used;
16715  } char_array;
16716  
16717 +#define pid_t int
16718  typedef struct {
16719         pid_t *ptr;
16720         size_t used;
16721 @@ -58,57 +54,68 @@
16722  typedef struct {
16723         PLUGIN_DATA;
16724         buffer_pid_t cgi_pid;
16725 -       
16726 +
16727         buffer *tmp_buf;
16728 -       buffer *parse_response;
16729 -       
16730 +
16731 +       http_resp *resp;
16732 +
16733         plugin_config **config_storage;
16734 -       
16735 -       plugin_config conf; 
16736 +
16737 +       plugin_config conf;
16738  } plugin_data;
16739  
16740 +typedef enum {
16741 +       CGI_STATE_UNSET,
16742 +       CGI_STATE_CONNECTING,
16743 +       CGI_STATE_READ_RESPONSE_HEADER,
16744 +       CGI_STATE_READ_RESPONSE_CONTENT
16745 +} cgi_state_t;
16746 +
16747  typedef struct {
16748         pid_t pid;
16749 -       int fd;
16750 -       int fde_ndx; /* index into the fd-event buffer */
16751 -       
16752 -       connection *remote_conn;  /* dumb pointer */
16753 -       plugin_data *plugin_data; /* dumb pointer */
16754 -       
16755 -       buffer *response;
16756 -       buffer *response_header;
16757 -} handler_ctx;
16758  
16759 -static handler_ctx * cgi_handler_ctx_init() {
16760 -       handler_ctx *hctx = calloc(1, sizeof(*hctx));
16761 +       iosocket *sock;
16762  
16763 -       assert(hctx);
16764 -       
16765 -       hctx->response = buffer_init();
16766 -       hctx->response_header = buffer_init();
16767 -       
16768 -       return hctx;
16769 -}
16770 +       chunkqueue *rb;
16771 +       chunkqueue *wb;
16772  
16773 -static void cgi_handler_ctx_free(handler_ctx *hctx) {
16774 -       buffer_free(hctx->response);
16775 -       buffer_free(hctx->response_header);
16776 -       
16777 -       free(hctx);
16778 +       cgi_state_t state;
16779 +
16780 +       connection *remote_con;  /* dumb pointer */
16781 +} cgi_session;
16782 +
16783 +static cgi_session * cgi_session_init() {
16784 +       cgi_session *sess = calloc(1, sizeof(*sess));
16785 +       assert(sess);
16786 +
16787 +       sess->sock = iosocket_init();
16788 +       sess->wb = chunkqueue_init();
16789 +       sess->rb = chunkqueue_init();
16790 +
16791 +       return sess;
16792  }
16793  
16794 -enum {FDEVENT_HANDLED_UNSET, FDEVENT_HANDLED_FINISHED, FDEVENT_HANDLED_NOT_FINISHED, FDEVENT_HANDLED_ERROR};
16795 +static void cgi_session_free(cgi_session *sess) {
16796 +       if (!sess) return;
16797 +
16798 +       iosocket_free(sess->sock);
16799 +
16800 +       chunkqueue_free(sess->wb);
16801 +       chunkqueue_free(sess->rb);
16802 +
16803 +       free(sess);
16804 +}
16805  
16806  INIT_FUNC(mod_cgi_init) {
16807         plugin_data *p;
16808 -       
16809 +
16810         p = calloc(1, sizeof(*p));
16811  
16812         assert(p);
16813 -       
16814 +
16815         p->tmp_buf = buffer_init();
16816 -       p->parse_response = buffer_init();
16817 -       
16818 +       p->resp = http_response_init();
16819 +
16820         return p;
16821  }
16822  
16823 @@ -116,62 +123,62 @@
16824  FREE_FUNC(mod_cgi_free) {
16825         plugin_data *p = p_d;
16826         buffer_pid_t *r = &(p->cgi_pid);
16827 -       
16828 +
16829         UNUSED(srv);
16830 -       
16831 +
16832         if (p->config_storage) {
16833                 size_t i;
16834                 for (i = 0; i < srv->config_context->used; i++) {
16835                         plugin_config *s = p->config_storage[i];
16836 -                       
16837 +
16838                         array_free(s->cgi);
16839 -                       
16840 +
16841                         free(s);
16842                 }
16843                 free(p->config_storage);
16844         }
16845 -       
16846 +
16847  
16848         if (r->ptr) free(r->ptr);
16849 -       
16850 +
16851         buffer_free(p->tmp_buf);
16852 -       buffer_free(p->parse_response);
16853 -       
16854 +       http_response_free(p->resp);
16855 +
16856         free(p);
16857 -       
16858 +
16859         return HANDLER_GO_ON;
16860  }
16861  
16862  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
16863         plugin_data *p = p_d;
16864         size_t i = 0;
16865 -       
16866 -       config_values_t cv[] = { 
16867 +
16868 +       config_values_t cv[] = {
16869                 { "cgi.assign",                  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
16870                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET}
16871         };
16872  
16873         if (!p) return HANDLER_ERROR;
16874 -       
16875 +
16876         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
16877 -       
16878 +
16879         for (i = 0; i < srv->config_context->used; i++) {
16880                 plugin_config *s;
16881 -               
16882 +
16883                 s = calloc(1, sizeof(plugin_config));
16884                 assert(s);
16885 -               
16886 +
16887                 s->cgi    = array_init();
16888 -               
16889 +
16890                 cv[0].destination = s->cgi;
16891 -               
16892 +
16893                 p->config_storage[i] = s;
16894 -       
16895 +
16896                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
16897                         return HANDLER_ERROR;
16898                 }
16899         }
16900 -       
16901 +
16902         return HANDLER_GO_ON;
16903  }
16904  
16905 @@ -180,13 +187,13 @@
16906         int m = -1;
16907         size_t i;
16908         buffer_pid_t *r = &(p->cgi_pid);
16909 -       
16910 +
16911         UNUSED(srv);
16912  
16913         for (i = 0; i < r->used; i++) {
16914                 if (r->ptr[i] > m) m = r->ptr[i];
16915         }
16916 -       
16917 +
16918         if (r->size == 0) {
16919                 r->size = 16;
16920                 r->ptr = malloc(sizeof(*r->ptr) * r->size);
16921 @@ -194,321 +201,179 @@
16922                 r->size += 16;
16923                 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
16924         }
16925 -       
16926 +
16927         r->ptr[r->used++] = pid;
16928 -       
16929 +
16930         return m;
16931  }
16932  
16933  static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) {
16934         size_t i;
16935         buffer_pid_t *r = &(p->cgi_pid);
16936 -       
16937 +
16938         UNUSED(srv);
16939  
16940         for (i = 0; i < r->used; i++) {
16941                 if (r->ptr[i] == pid) break;
16942         }
16943 -       
16944 +
16945         if (i != r->used) {
16946                 /* found */
16947 -               
16948 +
16949                 if (i != r->used - 1) {
16950                         r->ptr[i] = r->ptr[r->used - 1];
16951                 }
16952                 r->used--;
16953         }
16954 -       
16955 +
16956         return 0;
16957  }
16958  
16959 -static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
16960 -       char *ns;
16961 -       const char *s;
16962 -       int line = 0;
16963 -       
16964 -       UNUSED(srv);
16965 -       
16966 -       buffer_copy_string_buffer(p->parse_response, in);
16967 -       
16968 -       for (s = p->parse_response->ptr; 
16969 -            NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n'))); 
16970 -            s = ns + (eol == EOL_RN ? 2 : 1), line++) {
16971 -               const char *key, *value;
16972 -               int key_len;
16973 -               data_string *ds;
16974 -               
16975 -               ns[0] = '\0';
16976 -               
16977 -               if (line == 0 && 
16978 -                   0 == strncmp(s, "HTTP/1.", 7)) {
16979 -                       /* non-parsed header ... we parse them anyway */
16980 -                       
16981 -                       if ((s[7] == '1' ||
16982 -                            s[7] == '0') &&
16983 -                           s[8] == ' ') {
16984 -                               int status;
16985 -                               /* after the space should be a status code for us */
16986 -                               
16987 -                               status = strtol(s+9, NULL, 10);
16988 -                               
16989 -                               if (con->http_status >= 100 &&
16990 -                                   con->http_status < 1000) {
16991 -                                       /* we expected 3 digits and didn't got them */
16992 -                                       con->parsed_response |= HTTP_STATUS;
16993 -                                       con->http_status = status;
16994 -                               }
16995 -                       }
16996 -               } else {
16997 -               
16998 -                       key = s;
16999 -                       if (NULL == (value = strchr(s, ':'))) {
17000 -                               /* we expect: "<key>: <value>\r\n" */
17001 -                               continue;
17002 -                       }
17003 -                       
17004 -                       key_len = value - key;
17005 -                       value += 1;
17006 -                       
17007 -                       /* skip LWS */
17008 -                       while (*value == ' ' || *value == '\t') value++;
17009 -                       
17010 -                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
17011 -                               ds = data_response_init();
17012 -                       }
17013 -                       buffer_copy_string_len(ds->key, key, key_len);
17014 -                       buffer_copy_string(ds->value, value);
17015 -                       
17016 -                       array_insert_unique(con->response.headers, (data_unset *)ds);
17017 -                       
17018 -                       switch(key_len) {
17019 -                       case 4:
17020 -                               if (0 == strncasecmp(key, "Date", key_len)) {
17021 -                                       con->parsed_response |= HTTP_DATE;
17022 -                               }
17023 -                               break;
17024 -                       case 6:
17025 -                               if (0 == strncasecmp(key, "Status", key_len)) {
17026 -                                       con->http_status = strtol(value, NULL, 10);
17027 -                                       con->parsed_response |= HTTP_STATUS;
17028 -                               }
17029 -                               break;
17030 -                       case 8:
17031 -                               if (0 == strncasecmp(key, "Location", key_len)) {
17032 -                                       con->parsed_response |= HTTP_LOCATION;
17033 -                               }
17034 -                               break;
17035 -                       case 10:
17036 -                               if (0 == strncasecmp(key, "Connection", key_len)) {
17037 -                                       con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
17038 -                                       con->parsed_response |= HTTP_CONNECTION;
17039 -                               }
17040 -                               break;
17041 -                       case 14:
17042 -                               if (0 == strncasecmp(key, "Content-Length", key_len)) {
17043 -                                       con->response.content_length = strtol(value, NULL, 10);
17044 -                                       con->parsed_response |= HTTP_CONTENT_LENGTH;
17045 -                               }
17046 -                               break;
17047 -                       default:
17048 -                               break;
17049 -                       }
17050 -               }
17051 -       }
17052 -       
17053 -       /* CGI/1.1 rev 03 - 7.2.1.2 */
17054 -       if ((con->parsed_response & HTTP_LOCATION) &&
17055 -           !(con->parsed_response & HTTP_STATUS)) {
17056 -               con->http_status = 302;
17057 +static int cgi_demux_response(server *srv, connection *con, plugin_data *p) {
17058 +       cgi_session *sess = con->plugin_ctx[p->id];
17059 +       chunk *c = NULL;
17060 +
17061 +       switch(srv->network_backend_read(srv, con, sess->sock, sess->rb)) {
17062 +       case NETWORK_STATUS_SUCCESS:
17063 +               /* we got content */
17064 +               break;
17065 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
17066 +               return 0;
17067 +       case NETWORK_STATUS_CONNECTION_CLOSE:
17068 +               /* this is a bit too early */
17069 +               ERROR("%s", "cgi-connection got closed before we read the response-header (CGI died ?)");
17070 +               return -1;
17071 +       default:
17072 +               /* oops */
17073 +               ERROR("%s", "oops, read-pipe-read failed and I don't know why");
17074 +               return -1;
17075         }
17076 -       
17077 -       return 0;
17078 -}
17079  
17080 +       /* looks like we got some content
17081 +       *
17082 +       * split off the header from the incoming stream
17083 +       */
17084  
17085 -static int cgi_demux_response(server *srv, handler_ctx *hctx) {
17086 -       plugin_data *p    = hctx->plugin_data;
17087 -       connection  *con  = hctx->remote_conn;
17088 -       
17089 -       while(1) {
17090 -               int n;
17091 -               
17092 -               buffer_prepare_copy(hctx->response, 1024);
17093 -               if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
17094 -                       if (errno == EAGAIN || errno == EINTR) {
17095 -                               /* would block, wait for signal */
17096 -                               return FDEVENT_HANDLED_NOT_FINISHED;
17097 -                       }
17098 -                       /* error */
17099 -                       log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
17100 -                       return FDEVENT_HANDLED_ERROR;
17101 -               }
17102 -               
17103 -               if (n == 0) {
17104 -                       /* read finished */
17105 -                       
17106 -                       con->file_finished = 1;
17107 -                       
17108 -                       /* send final chunk */
17109 -                       http_chunk_append_mem(srv, con, NULL, 0);
17110 -                       joblist_append(srv, con);
17111 -                       
17112 -                       return FDEVENT_HANDLED_FINISHED;
17113 -               }
17114 -               
17115 -               hctx->response->ptr[n] = '\0';
17116 -               hctx->response->used = n+1;
17117 -               
17118 -               /* split header from body */
17119 -               
17120 -               if (con->file_started == 0) {
17121 -                       char *c;
17122 -                       int in_header = 0;
17123 -                       int header_end = 0;
17124 -                       int cp, eol = EOL_UNSET;
17125 -                       size_t used = 0;
17126 -                       
17127 -                       buffer_append_string_buffer(hctx->response_header, hctx->response);
17128 -                       
17129 -                       /* nph (non-parsed headers) */
17130 -                       if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
17131 -                       
17132 -                       /* search for the \r\n\r\n or \n\n in the string */
17133 -                       for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
17134 -                               if (*c == ':') in_header = 1;
17135 -                               else if (*c == '\n') {
17136 -                                       if (in_header == 0) {
17137 -                                               /* got a response without a response header */
17138 -                                               
17139 -                                               c = NULL;
17140 -                                               header_end = 1;
17141 -                                               break;
17142 -                                       }
17143 -                                       
17144 -                                       if (eol == EOL_UNSET) eol = EOL_N;
17145 -                                       
17146 -                                       if (*(c+1) == '\n') {
17147 -                                               header_end = 1;
17148 -                                               break;
17149 -                                       }
17150 -                                       
17151 -                               } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
17152 -                                       if (in_header == 0) {
17153 -                                               /* got a response without a response header */
17154 -                                               
17155 -                                               c = NULL;
17156 -                                               header_end = 1;
17157 -                                               break;
17158 -                                       }
17159 -                                       
17160 -                                       if (eol == EOL_UNSET) eol = EOL_RN;
17161 -                                       
17162 -                                       if (used > 3 &&
17163 -                                           *(c+2) == '\r' && 
17164 -                                           *(c+3) == '\n') {
17165 -                                               header_end = 1;
17166 -                                               break;
17167 -                                       }
17168 -                                       
17169 -                                       /* skip the \n */
17170 -                                       c++;
17171 -                                       cp++;
17172 -                                       used--;
17173 +       if (con->file_started == 0) {
17174 +               size_t i;
17175 +               int have_content_length = 0;
17176 +
17177 +               http_response_reset(p->resp);
17178 +
17179 +               /* the response header is not fully received yet,
17180 +               *
17181 +               * extract the http-response header from the rb-cq
17182 +               */
17183 +               switch (http_response_parse_cq(sess->rb, p->resp)) {
17184 +               case PARSE_ERROR:
17185 +                       /* parsing failed */
17186 +
17187 +                       TRACE("%s", "response parser failed");
17188 +
17189 +                       con->http_status = 502; /* Bad Gateway */
17190 +                       return -1;
17191 +               case PARSE_NEED_MORE:
17192 +                       return 0;
17193 +               case PARSE_SUCCESS:
17194 +                       con->http_status = p->resp->status;
17195 +
17196 +                       chunkqueue_remove_finished_chunks(sess->rb);
17197 +
17198 +                       /* copy the http-headers */
17199 +                       for (i = 0; i < p->resp->headers->used; i++) {
17200 +                               const char *ign[] = { "Status", "Connection", NULL };
17201 +                               size_t j;
17202 +                               data_string *ds;
17203 +
17204 +                               data_string *header = (data_string *)p->resp->headers->data[i];
17205 +
17206 +                               /* some headers are ignored by default */
17207 +                               for (j = 0; ign[j]; j++) {
17208 +                                       if (0 == strcasecmp(ign[j], header->key->ptr)) break;
17209                                 }
17210 -                       }
17211 -                       
17212 -                       if (header_end) {
17213 -                               if (c == NULL) {
17214 -                                       /* no header, but a body */
17215 -                                       
17216 -                                       if (con->request.http_version == HTTP_VERSION_1_1) {
17217 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17218 -                                       }
17219 -                                       
17220 -                                       http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
17221 -                                       joblist_append(srv, con);
17222 -                               } else {
17223 -                                       size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
17224 -                                       size_t blen = hctx->response_header->used - hlen - 1;
17225 -                               
17226 -                                       /* a small hack: terminate after at the second \r */
17227 -                                       hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
17228 -                                       hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
17229 -                               
17230 -                                       /* parse the response header */
17231 -                                       cgi_response_parse(srv, con, p, hctx->response_header, eol);
17232 -                                       
17233 -                                       /* enable chunked-transfer-encoding */
17234 -                                       if (con->request.http_version == HTTP_VERSION_1_1 &&
17235 -                                           !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
17236 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17237 -                                       }
17238 -                                       
17239 -                                       if ((hctx->response->used != hlen) && blen > 0) {
17240 -                                               http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
17241 -                                               joblist_append(srv, con);
17242 -                                       }
17243 +                               if (ign[j]) continue;
17244 +
17245 +                               if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
17246 +                                       /* CGI/1.1 rev 03 - 7.2.1.2 */
17247 +                                       if (con->http_status == 0) con->http_status = 302;
17248 +                               } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
17249 +                                       have_content_length = 1;
17250                                 }
17251                                 
17252 -                               con->file_started = 1;
17253 +                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
17254 +                                       ds = data_response_init();
17255 +                               }
17256 +                               buffer_copy_string_buffer(ds->key, header->key);
17257 +                               buffer_copy_string_buffer(ds->value, header->value);
17258 +
17259 +                               array_insert_unique(con->response.headers, (data_unset *)ds);
17260                         }
17261 -               } else {
17262 -                       http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
17263 -                       joblist_append(srv, con);
17264 +
17265 +                       con->file_started = 1;
17266 +                       sess->state = CGI_STATE_READ_RESPONSE_CONTENT;
17267 +
17268 +                       if (con->request.http_version == HTTP_VERSION_1_1 &&
17269 +                           !have_content_length) {
17270 +                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17271 +                       }
17272 +
17273 +                       break;
17274                 }
17275 -               
17276 -#if 0          
17277 -               log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
17278 -#endif
17279         }
17280 -       
17281 -       return FDEVENT_HANDLED_NOT_FINISHED;
17282 +
17283 +       /* FIXME: pass the response-header to the other plugins to
17284 +       * setup the filter-queue
17285 +       *
17286 +       * - use next-queue instead of con->write_queue
17287 +       */
17288 +
17289 +       /* copy the content to the next cq */
17290 +       for (c = sess->rb->first; c; c = c->next) {
17291 +               http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
17292 +
17293 +               c->offset = c->mem->used - 1;
17294 +       }
17295 +
17296 +       chunkqueue_remove_finished_chunks(sess->rb);
17297 +       joblist_append(srv, con);
17298 +
17299 +       return 0;
17300  }
17301  
17302 -static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) {
17303 +static handler_t cgi_connection_close(server *srv, connection *con, plugin_data *p) {
17304 +       cgi_session *sess = con->plugin_ctx[p->id];
17305         int status;
17306         pid_t pid;
17307 -       plugin_data *p;
17308 -       connection  *con;
17309 -       
17310 -       if (NULL == hctx) return HANDLER_GO_ON;
17311 -       
17312 -       p    = hctx->plugin_data;
17313 -       con  = hctx->remote_conn;
17314 -       
17315 +
17316 +       if (NULL == sess) return HANDLER_GO_ON;
17317         if (con->mode != p->id) return HANDLER_GO_ON;
17318  
17319 -#ifndef __WIN32
17320 -       
17321 +#ifndef _WIN32
17322 +
17323         /* the connection to the browser went away, but we still have a connection
17324 -        * to the CGI script 
17325 +        * to the CGI script
17326          *
17327          * close cgi-connection
17328          */
17329 -       
17330 -       if (hctx->fd != -1) {
17331 +
17332 +       if (sess->sock->fd != -1) {
17333                 /* close connection to the cgi-script */
17334 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
17335 -               fdevent_unregister(srv->ev, hctx->fd);
17336 -               
17337 -               if (close(hctx->fd)) {
17338 -                       log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
17339 -               }
17340 -               
17341 -               hctx->fd = -1;
17342 -               hctx->fde_ndx = -1;
17343 +               fdevent_event_del(srv->ev, sess->sock);
17344 +               fdevent_unregister(srv->ev, sess->sock);
17345         }
17346 -       
17347 -       pid = hctx->pid;
17348 -       
17349 +
17350 +       pid = sess->pid;
17351 +
17352         con->plugin_ctx[p->id] = NULL;
17353 -       
17354 +
17355         /* is this a good idea ? */
17356 -       cgi_handler_ctx_free(hctx);
17357 -       
17358 +       cgi_session_free(sess);
17359 +       sess = NULL;
17360 +
17361         /* if waitpid hasn't been called by response.c yet, do it here */
17362         if (pid) {
17363                 /* check if the CGI-script is already gone */
17364 +#ifndef _WIN32
17365                 switch(waitpid(pid, &status, WNOHANG)) {
17366                 case 0:
17367                         /* not finished yet */
17368 @@ -519,35 +384,35 @@
17369                 case -1:
17370                         /* */
17371                         if (errno == EINTR) break;
17372 -                       
17373 -                       /* 
17374 -                        * errno == ECHILD happens if _subrequest catches the process-status before 
17375 +
17376 +                       /*
17377 +                        * errno == ECHILD happens if _subrequest catches the process-status before
17378                          * we have read the response of the cgi process
17379 -                        * 
17380 +                        *
17381                          * -> catch status
17382                          * -> WAIT_FOR_EVENT
17383                          * -> read response
17384                          * -> we get here with waitpid == ECHILD
17385 -                        * 
17386 +                        *
17387                          */
17388                         if (errno == ECHILD) return HANDLER_GO_ON;
17389 -                       
17390 +
17391                         log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
17392                         return HANDLER_ERROR;
17393                 default:
17394                         /* Send an error if we haven't sent any data yet */
17395                         if (0 == con->file_started) {
17396                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
17397 -                               con->http_status = 500;
17398 +                               if (con->http_status == 0) con->http_status = 500;
17399                                 con->mode = DIRECT;
17400                         }
17401 -                               
17402 +
17403                         if (WIFEXITED(status)) {
17404  #if 0
17405                                 log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", pid);
17406  #endif
17407                                 pid = 0;
17408 -                               
17409 +
17410                                 return HANDLER_GO_ON;
17411                         } else {
17412                                 log_error_write(srv, __FILE__, __LINE__, "sd", "cgi died, pid:", pid);
17413 @@ -555,122 +420,126 @@
17414                                 return HANDLER_GO_ON;
17415                         }
17416                 }
17417 -               
17418 -       
17419 +
17420 +
17421                 kill(pid, SIGTERM);
17422 -               
17423 +#endif
17424                 /* cgi-script is still alive, queue the PID for removal */
17425                 cgi_pid_add(srv, p, pid);
17426         }
17427 -#endif 
17428 +#endif
17429         return HANDLER_GO_ON;
17430  }
17431  
17432  static handler_t cgi_connection_close_callback(server *srv, connection *con, void *p_d) {
17433         plugin_data *p = p_d;
17434 -       
17435 -       return cgi_connection_close(srv, con->plugin_ctx[p->id]);
17436 +
17437 +       return cgi_connection_close(srv, con, p);
17438  }
17439  
17440  
17441  static handler_t cgi_handle_fdevent(void *s, void *ctx, int revents) {
17442         server      *srv  = (server *)s;
17443 -       handler_ctx *hctx = ctx;
17444 -       connection  *con  = hctx->remote_conn;
17445 -       
17446 -       joblist_append(srv, con);
17447 -       
17448 -       if (hctx->fd == -1) {
17449 -               log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "invalid cgi-fd");
17450 -               
17451 -               return HANDLER_ERROR;
17452 -       }
17453 -       
17454 +       cgi_session *sess = ctx;
17455 +       connection  *con  = sess->remote_con;
17456 +       chunk *c;
17457 +
17458         if (revents & FDEVENT_IN) {
17459 -               switch (cgi_demux_response(srv, hctx)) {
17460 -               case FDEVENT_HANDLED_NOT_FINISHED:
17461 +               switch (sess->state) {
17462 +               case CGI_STATE_READ_RESPONSE_HEADER:
17463 +                       /* parse the header and set file-started, the demuxer will care about it */
17464 +                       joblist_append(srv, con);
17465 +
17466                         break;
17467 -               case FDEVENT_HANDLED_FINISHED:
17468 -                       /* we are done */
17469 -                       
17470 +               case CGI_STATE_READ_RESPONSE_CONTENT:
17471 +                       /* just forward the content to the out-going queue */
17472 +
17473 +                       chunkqueue_remove_finished_chunks(sess->rb);
17474 +
17475 +                       switch (srv->network_backend_read(srv, sess->remote_con, sess->sock, sess->rb)) {
17476 +                       case NETWORK_STATUS_CONNECTION_CLOSE:
17477 +                               fdevent_event_del(srv->ev, sess->sock);
17478 +
17479 +                               /* the connection is gone
17480 +                                * make the connect */
17481 +                               sess->remote_con->file_finished = 1;
17482  #if 0
17483 -                       log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "finished");
17484 +                               fdevent_event_del(srv->ev, sess->sock);
17485  #endif
17486 -                       cgi_connection_close(srv, hctx);
17487 -                       
17488 -                       /* if we get a IN|HUP and have read everything don't exec the close twice */ 
17489 -                       return HANDLER_FINISHED;
17490 -               case FDEVENT_HANDLED_ERROR:
17491 -                       connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
17492 -                       con->http_status = 500;
17493 -                       con->mode = DIRECT;
17494 -                       
17495 -                       log_error_write(srv, __FILE__, __LINE__, "s", "demuxer failed: ");
17496 +                       case NETWORK_STATUS_SUCCESS:
17497 +                               /* read even more, do we have all the content */
17498 +
17499 +                               /* how much do we want to read ? */
17500 +                               
17501 +                               /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
17502 +
17503 +                               chunkqueue_remove_finished_chunks(sess->rb);
17504 +
17505 +                               /* copy the content to the next cq */
17506 +                               for (c = sess->rb->first; c; c = c->next) {
17507 +                                       if (c->mem->used == 0) continue;
17508 +
17509 +                                       http_chunk_append_mem(srv, sess->remote_con, c->mem->ptr + c->offset, c->mem->used - c->offset);
17510 +       
17511 +                                       c->offset = c->mem->used - 1;
17512 +
17513 +                               }
17514 +                               chunkqueue_remove_finished_chunks(sess->rb);
17515 +
17516 +                               if (sess->remote_con->file_finished) {
17517 +                                       /* send final HTTP-Chunk packet */
17518 +                                       http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
17519 +                               }
17520 +                               
17521 +                               break;
17522 +                       default:
17523 +                               ERROR("%s", "oops, we failed to read");
17524 +                               break;
17525 +                       }
17526 +
17527 +                       joblist_append(srv, sess->remote_con);
17528 +                       break;
17529 +               default:
17530 +                       TRACE("unexpected state for a FDEVENT_IN: %d", sess->state);
17531                         break;
17532                 }
17533         }
17534 -       
17535 +
17536         if (revents & FDEVENT_OUT) {
17537                 /* nothing to do */
17538         }
17539 -       
17540 +
17541         /* perhaps this issue is already handled */
17542         if (revents & FDEVENT_HUP) {
17543 -               /* check if we still have a unfinished header package which is a body in reality */
17544 -               if (con->file_started == 0 &&
17545 -                   hctx->response_header->used) {
17546 -                       con->file_started = 1;
17547 -                       http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
17548 -                       joblist_append(srv, con);
17549 -               }
17550 -               
17551 -               if (con->file_finished == 0) {
17552 -                       http_chunk_append_mem(srv, con, NULL, 0);
17553 -                       joblist_append(srv, con);
17554 -               }
17555 -               
17556                 con->file_finished = 1;
17557 -               
17558 -               if (chunkqueue_is_empty(con->write_queue)) {
17559 -                       /* there is nothing left to write */
17560 -                       connection_set_state(srv, con, CON_STATE_RESPONSE_END);
17561 -               } else {
17562 -                       /* used the write-handler to finish the request on demand */
17563 -                       
17564 -               }
17565 -               
17566 -# if 0
17567 -               log_error_write(srv, __FILE__, __LINE__, "sddd", "got HUP from cgi", con->fd, hctx->fd, revents);
17568 -# endif
17569 -               
17570 -               /* rtsigs didn't liked the close */
17571 -               cgi_connection_close(srv, hctx);
17572 +
17573 +               fdevent_event_del(srv->ev, sess->sock);
17574 +
17575 +               /* someone has to close this socket now :) */
17576 +               http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
17577 +               joblist_append(srv, sess->remote_con);
17578         } else if (revents & FDEVENT_ERR) {
17579                 con->file_finished = 1;
17580 -               
17581 +
17582                 /* kill all connections to the cgi process */
17583 -               cgi_connection_close(srv, hctx);
17584 -#if 1
17585 -               log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR");
17586 -#endif                 
17587 -               return HANDLER_ERROR;
17588 +               fdevent_event_del(srv->ev, sess->sock);
17589         }
17590 -       
17591 +
17592         return HANDLER_FINISHED;
17593  }
17594  
17595  
17596  static int cgi_env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
17597         char *dst;
17598 -       
17599 +
17600         if (!key || !val) return -1;
17601 -       
17602 +
17603         dst = malloc(key_len + val_len + 3);
17604         memcpy(dst, key, key_len);
17605         dst[key_len] = '=';
17606         /* add the \0 from the value */
17607         memcpy(dst + key_len + 1, val, val_len + 1);
17608 -       
17609 +
17610         if (env->size == 0) {
17611                 env->size = 16;
17612                 env->ptr = malloc(env->size * sizeof(*env->ptr));
17613 @@ -678,45 +547,45 @@
17614                 env->size += 16;
17615                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
17616         }
17617 -       
17618 +
17619         env->ptr[env->used++] = dst;
17620 -       
17621 +
17622         return 0;
17623  }
17624  
17625  static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *cgi_handler) {
17626         pid_t pid;
17627 -       
17628 +
17629  #ifdef HAVE_IPV6
17630         char b2[INET6_ADDRSTRLEN + 1];
17631  #endif
17632 -       
17633 +
17634         int to_cgi_fds[2];
17635         int from_cgi_fds[2];
17636         struct stat st;
17637 -       
17638 -#ifndef __WIN32        
17639 -       
17640 +
17641 +#ifndef _WIN32
17642 +
17643         if (cgi_handler->used > 1) {
17644                 /* stat the exec file */
17645                 if (-1 == (stat(cgi_handler->ptr, &st))) {
17646 -                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
17647 +                       log_error_write(srv, __FILE__, __LINE__, "sbss",
17648                                         "stat for cgi-handler", cgi_handler,
17649                                         "failed:", strerror(errno));
17650                         return -1;
17651                 }
17652         }
17653 -       
17654 +
17655         if (pipe(to_cgi_fds)) {
17656                 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
17657                 return -1;
17658         }
17659 -       
17660 +
17661         if (pipe(from_cgi_fds)) {
17662                 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
17663                 return -1;
17664         }
17665 -       
17666 +
17667         /* fork, execve */
17668         switch (pid = fork()) {
17669         case 0: {
17670 @@ -730,44 +599,40 @@
17671                 char *c;
17672                 const char *s;
17673                 server_socket *srv_sock = con->srv_socket;
17674 -               
17675 +
17676                 /* move stdout to from_cgi_fd[1] */
17677                 close(STDOUT_FILENO);
17678                 dup2(from_cgi_fds[1], STDOUT_FILENO);
17679                 close(from_cgi_fds[1]);
17680                 /* not needed */
17681                 close(from_cgi_fds[0]);
17682 -               
17683 +
17684                 /* move the stdin to to_cgi_fd[0] */
17685                 close(STDIN_FILENO);
17686                 dup2(to_cgi_fds[0], STDIN_FILENO);
17687                 close(to_cgi_fds[0]);
17688                 /* not needed */
17689                 close(to_cgi_fds[1]);
17690 -               
17691 -               /* HACK: 
17692 -                * this is not nice, but it works
17693 -                *
17694 -                * we feed the stderr of the CGI to our errorlog, if possible
17695 +
17696 +               /**
17697 +                * FIXME: add a event-handler for STDERR_FILENO and let it LOG()
17698                  */
17699 -               if (srv->errorlog_mode == ERRORLOG_FILE) {
17700 -                       close(STDERR_FILENO);
17701 -                       dup2(srv->errorlog_fd, STDERR_FILENO);
17702 -               }
17703 -               
17704 +
17705 +               close(STDERR_FILENO);
17706 +
17707                 /* create environment */
17708                 env.ptr = NULL;
17709                 env.size = 0;
17710                 env.used = 0;
17711 -               
17712 +
17713                 cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
17714  
17715                 if (!buffer_is_empty(con->server_name)) {
17716                         cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
17717                 } else {
17718  #ifdef HAVE_IPV6
17719 -                       s = inet_ntop(srv_sock->addr.plain.sa_family, 
17720 -                                     srv_sock->addr.plain.sa_family == AF_INET6 ? 
17721 +                       s = inet_ntop(srv_sock->addr.plain.sa_family,
17722 +                                     srv_sock->addr.plain.sa_family == AF_INET6 ?
17723                                       (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
17724                                       (const void *) &(srv_sock->addr.ipv4.sin_addr),
17725                                       b2, sizeof(b2)-1);
17726 @@ -779,10 +644,10 @@
17727                 cgi_env_add(&env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
17728  
17729                 s = get_http_version_name(con->request.http_version);
17730 -               
17731 +
17732                 cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
17733 -               
17734 -               ltostr(buf, 
17735 +
17736 +               ltostr(buf,
17737  #ifdef HAVE_IPV6
17738                         ntohs(srv_sock->addr.plain.sa_family == AF_INET6 ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
17739  #else
17740 @@ -790,10 +655,10 @@
17741  #endif
17742                         );
17743                 cgi_env_add(&env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
17744 -               
17745 +
17746  #ifdef HAVE_IPV6
17747 -               s = inet_ntop(srv_sock->addr.plain.sa_family, 
17748 -                             srv_sock->addr.plain.sa_family == AF_INET6 ? 
17749 +               s = inet_ntop(srv_sock->addr.plain.sa_family,
17750 +                             srv_sock->addr.plain.sa_family == AF_INET6 ?
17751                               (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
17752                               (const void *) &(srv_sock->addr.ipv4.sin_addr),
17753                               b2, sizeof(b2)-1);
17754 @@ -811,15 +676,18 @@
17755                 cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
17756                 if (!buffer_is_empty(con->uri.query)) {
17757                         cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
17758 +               } else {
17759 +                       /* set a empty QUERY_STRING */
17760 +                       cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
17761                 }
17762                 if (!buffer_is_empty(con->request.orig_uri)) {
17763                         cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
17764                 }
17765 -               
17766 -               
17767 +
17768 +
17769  #ifdef HAVE_IPV6
17770 -               s = inet_ntop(con->dst_addr.plain.sa_family, 
17771 -                             con->dst_addr.plain.sa_family == AF_INET6 ? 
17772 +               s = inet_ntop(con->dst_addr.plain.sa_family,
17773 +                             con->dst_addr.plain.sa_family == AF_INET6 ?
17774                               (const void *) &(con->dst_addr.ipv6.sin6_addr) :
17775                               (const void *) &(con->dst_addr.ipv4.sin_addr),
17776                               b2, sizeof(b2)-1);
17777 @@ -828,7 +696,7 @@
17778  #endif
17779                 cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
17780  
17781 -               ltostr(buf, 
17782 +               ltostr(buf,
17783  #ifdef HAVE_IPV6
17784                         ntohs(con->dst_addr.plain.sa_family == AF_INET6 ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
17785  #else
17786 @@ -836,19 +704,19 @@
17787  #endif
17788                         );
17789                 cgi_env_add(&env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
17790 -               
17791 +
17792                 if (!buffer_is_empty(con->authed_user)) {
17793                         cgi_env_add(&env, CONST_STR_LEN("REMOTE_USER"),
17794                                     CONST_BUF_LEN(con->authed_user));
17795                 }
17796 -               
17797 +
17798                 /* request.content_length < SSIZE_MAX, see request.c */
17799                 ltostr(buf, con->request.content_length);
17800                 cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
17801                 cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
17802                 cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
17803                 cgi_env_add(&env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
17804 -               
17805 +
17806                 /* for valgrind */
17807                 if (NULL != (s = getenv("LD_PRELOAD"))) {
17808                         cgi_env_add(&env, CONST_STR_LEN("LD_PRELOAD"), s, strlen(s));
17809 @@ -863,24 +731,24 @@
17810                         cgi_env_add(&env, CONST_STR_LEN("SYSTEMROOT"), s, strlen(s));
17811                 }
17812  #endif
17813 -               
17814 +
17815                 for (n = 0; n < con->request.headers->used; n++) {
17816                         data_string *ds;
17817 -                       
17818 +
17819                         ds = (data_string *)con->request.headers->data[n];
17820 -                       
17821 +
17822                         if (ds->value->used && ds->key->used) {
17823                                 size_t j;
17824 -                               
17825 +
17826                                 buffer_reset(p->tmp_buf);
17827 -                               
17828 +
17829                                 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
17830                                         buffer_copy_string(p->tmp_buf, "HTTP_");
17831                                         p->tmp_buf->used--; /* strip \0 after HTTP_ */
17832                                 }
17833 -                               
17834 +
17835                                 buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
17836 -                               
17837 +
17838                                 for (j = 0; j < ds->key->used - 1; j++) {
17839                                         char cr = '_';
17840                                         if (light_isalpha(ds->key->ptr[j])) {
17841 @@ -893,46 +761,46 @@
17842                                         p->tmp_buf->ptr[p->tmp_buf->used++] = cr;
17843                                 }
17844                                 p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
17845 -                               
17846 +
17847                                 cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
17848                         }
17849                 }
17850 -               
17851 +
17852                 for (n = 0; n < con->environment->used; n++) {
17853                         data_string *ds;
17854 -                       
17855 +
17856                         ds = (data_string *)con->environment->data[n];
17857 -                       
17858 +
17859                         if (ds->value->used && ds->key->used) {
17860                                 size_t j;
17861 -                               
17862 +
17863                                 buffer_reset(p->tmp_buf);
17864 -                               
17865 +
17866                                 buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
17867 -                               
17868 +
17869                                 for (j = 0; j < ds->key->used - 1; j++) {
17870 -                                       p->tmp_buf->ptr[p->tmp_buf->used++] = 
17871 -                                               isalpha((unsigned char)ds->key->ptr[j]) ? 
17872 +                                       p->tmp_buf->ptr[p->tmp_buf->used++] =
17873 +                                               isalpha((unsigned char)ds->key->ptr[j]) ?
17874                                                 toupper((unsigned char)ds->key->ptr[j]) : '_';
17875                                 }
17876                                 p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
17877 -                               
17878 +
17879                                 cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
17880                         }
17881                 }
17882 -               
17883 +
17884                 if (env.size == env.used) {
17885                         env.size += 16;
17886                         env.ptr = realloc(env.ptr, env.size * sizeof(*env.ptr));
17887                 }
17888 -               
17889 +
17890                 env.ptr[env.used] = NULL;
17891 -               
17892 +
17893                 /* set up args */
17894                 argc = 3;
17895                 args = malloc(sizeof(*args) * argc);
17896                 i = 0;
17897 -               
17898 +
17899                 if (cgi_handler->used > 1) {
17900                         args[i++] = cgi_handler->ptr;
17901                 }
17902 @@ -942,7 +810,7 @@
17903                 /* search for the last / */
17904                 if (NULL != (c = strrchr(con->physical.path->ptr, '/'))) {
17905                         *c = '\0';
17906 -                       
17907 +
17908                         /* change to the physical directory */
17909                         if (-1 == chdir(con->physical.path->ptr)) {
17910                                 log_error_write(srv, __FILE__, __LINE__, "ssb", "chdir failed:", strerror(errno), con->physical.path);
17911 @@ -952,14 +820,14 @@
17912  
17913                 /* we don't need the client socket */
17914                 for (i = 3; i < 256; i++) {
17915 -                       if (i != srv->errorlog_fd) close(i);
17916 +                       close(i);
17917                 }
17918 -               
17919 +
17920                 /* exec the cgi */
17921                 execve(args[0], args, env.ptr);
17922 -               
17923 +
17924                 log_error_write(srv, __FILE__, __LINE__, "sss", "CGI failed:", strerror(errno), args[0]);
17925 -               
17926 +
17927                 /* */
17928                 SEGFAULT();
17929                 break;
17930 @@ -969,16 +837,16 @@
17931                 log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno));
17932                 break;
17933         default: {
17934 -               handler_ctx *hctx;
17935 +               cgi_session *sess;
17936                 /* father */
17937  
17938                 close(from_cgi_fds[1]);
17939                 close(to_cgi_fds[0]);
17940 -               
17941 +
17942                 if (con->request.content_length) {
17943                         chunkqueue *cq = con->request_content_queue;
17944                         chunk *c;
17945 -               
17946 +
17947                         assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
17948  
17949                         /* there is content to send */
17950 @@ -993,16 +861,16 @@
17951                                                 if (-1 == c->file.fd &&  /* open the file if not already open */
17952                                                     -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
17953                                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
17954 -                                       
17955 +
17956                                                         close(from_cgi_fds[0]);
17957                                                         close(to_cgi_fds[1]);
17958                                                         return -1;
17959                                                 }
17960  
17961                                                 c->file.mmap.length = c->file.length;
17962 -                               
17963 +
17964                                                 if (MAP_FAILED == (c->file.mmap.start = mmap(0,  c->file.mmap.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
17965 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", 
17966 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
17967                                                                         strerror(errno), c->file.name,  c->file.fd);
17968  
17969                                                         close(from_cgi_fds[0]);
17970 @@ -1012,7 +880,7 @@
17971  
17972                                                 close(c->file.fd);
17973                                                 c->file.fd = -1;
17974 -       
17975 +
17976                                                 /* chunk_reset() or chunk_free() will cleanup for us */
17977                                         }
17978  
17979 @@ -1020,7 +888,7 @@
17980                                                 switch(errno) {
17981                                                 case ENOSPC:
17982                                                         con->http_status = 507;
17983 -               
17984 +
17985                                                         break;
17986                                                 default:
17987                                                         con->http_status = 403;
17988 @@ -1033,7 +901,7 @@
17989                                                 switch(errno) {
17990                                                 case ENOSPC:
17991                                                         con->http_status = 507;
17992 -               
17993 +
17994                                                         break;
17995                                                 default:
17996                                                         con->http_status = 403;
17997 @@ -1056,103 +924,95 @@
17998                 }
17999  
18000                 close(to_cgi_fds[1]);
18001 -                               
18002 +
18003                 /* register PID and wait for them asyncronously */
18004                 con->mode = p->id;
18005                 buffer_reset(con->physical.path);
18006 -               
18007 -               hctx = cgi_handler_ctx_init();
18008 -               
18009 -               hctx->remote_conn = con;
18010 -               hctx->plugin_data = p;
18011 -               hctx->pid = pid;
18012 -               hctx->fd = from_cgi_fds[0];
18013 -               hctx->fde_ndx = -1;
18014 -               
18015 -               con->plugin_ctx[p->id] = hctx;
18016 -               
18017 -               fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx);
18018 -               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
18019 -               
18020 -               if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
18021 +
18022 +               sess = cgi_session_init();
18023 +
18024 +               sess->remote_con = con;
18025 +               sess->pid = pid;
18026 +
18027 +               assert(sess->sock);
18028 +
18029 +               sess->sock->fd = from_cgi_fds[0];
18030 +               sess->sock->type = IOSOCKET_TYPE_PIPE;
18031 +
18032 +               if (-1 == fdevent_fcntl_set(srv->ev, sess->sock)) {
18033                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
18034 -                       
18035 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18036 -                       fdevent_unregister(srv->ev, hctx->fd);
18037 -                       
18038 -                       log_error_write(srv, __FILE__, __LINE__, "sd", "cgi close:", hctx->fd);
18039 -                       
18040 -                       close(hctx->fd);
18041 -                       
18042 -                       cgi_handler_ctx_free(hctx);
18043 -                       
18044 -                       con->plugin_ctx[p->id] = NULL;
18045 -                       
18046 +
18047 +                       cgi_session_free(sess);
18048 +
18049                         return -1;
18050                 }
18051 -               
18052 +
18053 +               con->plugin_ctx[p->id] = sess;
18054 +
18055 +               fdevent_register(srv->ev, sess->sock, cgi_handle_fdevent, sess);
18056 +               fdevent_event_add(srv->ev, sess->sock, FDEVENT_IN);
18057 +
18058 +               sess->state = CGI_STATE_READ_RESPONSE_HEADER;
18059 +
18060                 break;
18061         }
18062         }
18063 -       
18064 +
18065         return 0;
18066  #else
18067         return -1;
18068  #endif
18069  }
18070  
18071 -#define PATCH(x) \
18072 -       p->conf.x = s->x;
18073  static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p) {
18074         size_t i, j;
18075         plugin_config *s = p->config_storage[0];
18076 -       
18077 -       PATCH(cgi);
18078 -       
18079 +
18080 +       PATCH_OPTION(cgi);
18081 +
18082         /* skip the first, the global context */
18083         for (i = 1; i < srv->config_context->used; i++) {
18084                 data_config *dc = (data_config *)srv->config_context->data[i];
18085                 s = p->config_storage[i];
18086 -               
18087 +
18088                 /* condition didn't match */
18089                 if (!config_check_cond(srv, con, dc)) continue;
18090 -               
18091 +
18092                 /* merge config */
18093                 for (j = 0; j < dc->value->used; j++) {
18094                         data_unset *du = dc->value->data[j];
18095 -                       
18096 +
18097                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.assign"))) {
18098 -                               PATCH(cgi);
18099 +                               PATCH_OPTION(cgi);
18100                         }
18101                 }
18102         }
18103 -       
18104 +
18105         return 0;
18106  }
18107 -#undef PATCH
18108  
18109  URIHANDLER_FUNC(cgi_is_handled) {
18110         size_t k, s_len;
18111         plugin_data *p = p_d;
18112         buffer *fn = con->physical.path;
18113 -       
18114 +
18115         if (fn->used == 0) return HANDLER_GO_ON;
18116 -       
18117 +
18118         mod_cgi_patch_connection(srv, con, p);
18119 -       
18120 +
18121         s_len = fn->used - 1;
18122 -       
18123 +
18124         for (k = 0; k < p->conf.cgi->used; k++) {
18125                 data_string *ds = (data_string *)p->conf.cgi->data[k];
18126                 size_t ct_len = ds->key->used - 1;
18127 -               
18128 +
18129                 if (ds->key->used == 0) continue;
18130                 if (s_len < ct_len) continue;
18131 -               
18132 +
18133                 if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
18134                         if (cgi_create_env(srv, con, p, ds->value)) {
18135                                 con->http_status = 500;
18136 -                               
18137 +
18138                                 buffer_reset(con->physical.path);
18139                                 return HANDLER_FINISHED;
18140                         }
18141 @@ -1160,7 +1020,7 @@
18142                         break;
18143                 }
18144         }
18145 -       
18146 +
18147         return HANDLER_GO_ON;
18148  }
18149  
18150 @@ -1168,11 +1028,11 @@
18151         plugin_data *p = p_d;
18152         size_t ndx;
18153         /* the trigger handle only cares about lonely PID which we have to wait for */
18154 -#ifndef __WIN32
18155 +#ifndef _WIN32
18156  
18157         for (ndx = 0; ndx < p->cgi_pid.used; ndx++) {
18158                 int status;
18159 -               
18160 +
18161                 switch(waitpid(p->cgi_pid.ptr[ndx], &status, WNOHANG)) {
18162                 case 0:
18163                         /* not finished yet */
18164 @@ -1182,7 +1042,7 @@
18165                         break;
18166                 case -1:
18167                         log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
18168 -                       
18169 +
18170                         return HANDLER_ERROR;
18171                 default:
18172  
18173 @@ -1193,96 +1053,105 @@
18174                         } else {
18175                                 log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
18176                         }
18177 -                       
18178 +
18179                         cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]);
18180 -                       /* del modified the buffer structure 
18181 +                       /* del modified the buffer structure
18182                          * and copies the last entry to the current one
18183                          * -> recheck the current index
18184                          */
18185                         ndx--;
18186                 }
18187         }
18188 -#endif 
18189 +#endif
18190         return HANDLER_GO_ON;
18191  }
18192  
18193  SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {
18194         int status;
18195         plugin_data *p = p_d;
18196 -       handler_ctx *hctx = con->plugin_ctx[p->id];
18197 -       
18198 +       cgi_session *sess = con->plugin_ctx[p->id];
18199 +
18200         if (con->mode != p->id) return HANDLER_GO_ON;
18201 -       if (NULL == hctx) return HANDLER_GO_ON;
18202 -       
18203 +       if (NULL == sess) return HANDLER_GO_ON;
18204 +
18205 +       switch (cgi_demux_response(srv, con, p)) {
18206 +       case 0:
18207 +               break;
18208 +       case 1:
18209 +               cgi_connection_close(srv, con, p);
18210 +
18211 +               /* if we get a IN|HUP and have read everything don't exec the close twice */
18212 +               return HANDLER_FINISHED;
18213 +       case -1:
18214 +               cgi_connection_close(srv, con, p);
18215 +
18216 +               if (0 == con->http_status) con->http_status = 500;
18217 +               connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
18218 +               con->mode = DIRECT;
18219 +
18220 +               return HANDLER_FINISHED;
18221 +       }
18222 +
18223  #if 0
18224 -       log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", hctx, hctx->pid);
18225 -#endif 
18226 -       if (hctx->pid == 0) return HANDLER_FINISHED;
18227 -#ifndef __WIN32        
18228 -       switch(waitpid(hctx->pid, &status, WNOHANG)) {
18229 +       log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", sess, sess->pid);
18230 +#endif
18231 +       if (sess->pid == 0) return HANDLER_FINISHED;
18232 +#ifndef _WIN32
18233 +       switch(waitpid(sess->pid, &status, WNOHANG)) {
18234         case 0:
18235                 /* we only have for events here if we don't have the header yet,
18236                  * otherwise the event-handler will send us the incoming data */
18237 -               if (con->file_started) return HANDLER_FINISHED;
18238  
18239 -               return HANDLER_WAIT_FOR_EVENT;
18240 +               if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
18241 +               if (con->file_finished) return HANDLER_FINISHED;
18242 +
18243 +               return HANDLER_GO_ON;
18244         case -1:
18245                 if (errno == EINTR) return HANDLER_WAIT_FOR_EVENT;
18246 -               
18247 +
18248                 if (errno == ECHILD && con->file_started == 0) {
18249                         /*
18250 -                        * second round but still not response 
18251 +                        * second round but still not response
18252                          */
18253 -                       return HANDLER_WAIT_FOR_EVENT; 
18254 +                       return HANDLER_WAIT_FOR_EVENT;
18255                 }
18256 -               
18257 +
18258                 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
18259                 con->mode = DIRECT;
18260                 con->http_status = 500;
18261 -               
18262 -               hctx->pid = 0;
18263 -               
18264 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18265 -               fdevent_unregister(srv->ev, hctx->fd);
18266 -               
18267 -               if (close(hctx->fd)) {
18268 -                       log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
18269 -               }
18270 -               
18271 -               cgi_handler_ctx_free(hctx);
18272 -               
18273 +
18274 +               sess->pid = 0;
18275 +
18276 +               fdevent_event_del(srv->ev, sess->sock);
18277 +               fdevent_unregister(srv->ev, sess->sock);
18278 +
18279 +               cgi_session_free(sess);
18280 +               sess = NULL;
18281 +
18282                 con->plugin_ctx[p->id] = NULL;
18283 -               
18284 +
18285                 return HANDLER_FINISHED;
18286         default:
18287 -               /* cgi process exited cleanly 
18288 -                * 
18289 -                * check if we already got the response 
18290 -                */
18291 -               
18292 -               if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
18293 -               
18294 +               con->file_finished = 1;
18295 +
18296                 if (WIFEXITED(status)) {
18297                         /* nothing */
18298                 } else {
18299                         log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
18300 -                       
18301 +
18302                         con->mode = DIRECT;
18303                         con->http_status = 500;
18304 -                       
18305 +
18306                 }
18307 -               
18308 -               hctx->pid = 0;
18309 -               
18310 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18311 -               fdevent_unregister(srv->ev, hctx->fd);
18312 -               
18313 -               if (close(hctx->fd)) {
18314 -                       log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
18315 -               }
18316 -               
18317 -               cgi_handler_ctx_free(hctx);
18318 -               
18319 +
18320 +               sess->pid = 0;
18321 +
18322 +               fdevent_event_del(srv->ev, sess->sock);
18323 +               fdevent_unregister(srv->ev, sess->sock);
18324 +
18325 +               cgi_session_free(sess);
18326 +               sess = NULL;
18327 +
18328                 con->plugin_ctx[p->id] = NULL;
18329                 return HANDLER_FINISHED;
18330         }
18331 @@ -1306,8 +1175,8 @@
18332         p->init           = mod_cgi_init;
18333         p->cleanup        = mod_cgi_free;
18334         p->set_defaults   = mod_fastcgi_set_defaults;
18335 -       
18336 +
18337         p->data        = NULL;
18338 -       
18339 +
18340         return 0;
18341  }
18342 --- ../lighttpd-1.4.11/src/mod_cml.c    2006-01-30 13:51:48.000000000 +0200
18343 +++ lighttpd-1.4.12/src/mod_cml.c       2006-07-16 00:26:03.000000000 +0300
18344 @@ -4,7 +4,6 @@
18345  #include <stdlib.h>
18346  #include <string.h>
18347  #include <errno.h>
18348 -#include <unistd.h>
18349  #include <stdio.h>
18350  
18351  #include "buffer.h"
18352 @@ -20,50 +19,50 @@
18353  /* init the plugin data */
18354  INIT_FUNC(mod_cml_init) {
18355         plugin_data *p;
18356 -       
18357 +
18358         p = calloc(1, sizeof(*p));
18359 -       
18360 +
18361         p->basedir         = buffer_init();
18362         p->baseurl         = buffer_init();
18363         p->trigger_handler = buffer_init();
18364 -       
18365 +
18366         return p;
18367  }
18368  
18369  /* detroy the plugin data */
18370  FREE_FUNC(mod_cml_free) {
18371         plugin_data *p = p_d;
18372 -       
18373 +
18374         UNUSED(srv);
18375  
18376         if (!p) return HANDLER_GO_ON;
18377 -       
18378 +
18379         if (p->config_storage) {
18380                 size_t i;
18381                 for (i = 0; i < srv->config_context->used; i++) {
18382                         plugin_config *s = p->config_storage[i];
18383 -                       
18384 +
18385                         buffer_free(s->ext);
18386 -                       
18387 +
18388                         buffer_free(s->mc_namespace);
18389                         buffer_free(s->power_magnet);
18390                         array_free(s->mc_hosts);
18391 -                       
18392 +
18393  #if defined(HAVE_MEMCACHE_H)
18394                         if (s->mc) mc_free(s->mc);
18395  #endif
18396 -                       
18397 +
18398                         free(s);
18399                 }
18400                 free(p->config_storage);
18401         }
18402 -       
18403 +
18404         buffer_free(p->trigger_handler);
18405         buffer_free(p->basedir);
18406         buffer_free(p->baseurl);
18407 -       
18408 +
18409         free(p);
18410 -       
18411 +
18412         return HANDLER_GO_ON;
18413  }
18414  
18415 @@ -72,22 +71,22 @@
18416  SETDEFAULTS_FUNC(mod_cml_set_defaults) {
18417         plugin_data *p = p_d;
18418         size_t i = 0;
18419 -       
18420 -       config_values_t cv[] = { 
18421 +
18422 +       config_values_t cv[] = {
18423                 { "cml.extension",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
18424                 { "cml.memcache-hosts",         NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 1 */
18425                 { "cml.memcache-namespace",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
18426                 { "cml.power-magnet",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
18427                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
18428         };
18429 -       
18430 +
18431         if (!p) return HANDLER_ERROR;
18432 -       
18433 +
18434         p->config_storage = malloc(srv->config_context->used * sizeof(specific_config *));
18435 -       
18436 +
18437         for (i = 0; i < srv->config_context->used; i++) {
18438                 plugin_config *s;
18439 -               
18440 +
18441                 s = malloc(sizeof(plugin_config));
18442                 s->ext    = buffer_init();
18443                 s->mc_hosts       = array_init();
18444 @@ -96,87 +95,84 @@
18445  #if defined(HAVE_MEMCACHE_H)
18446                 s->mc = NULL;
18447  #endif
18448 -               
18449 +
18450                 cv[0].destination = s->ext;
18451                 cv[1].destination = s->mc_hosts;
18452                 cv[2].destination = s->mc_namespace;
18453                 cv[3].destination = s->power_magnet;
18454 -               
18455 +
18456                 p->config_storage[i] = s;
18457 -       
18458 +
18459                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
18460                         return HANDLER_ERROR;
18461                 }
18462 -               
18463 +
18464                 if (s->mc_hosts->used) {
18465  #if defined(HAVE_MEMCACHE_H)
18466                         size_t k;
18467                         s->mc = mc_new();
18468 -               
18469 +
18470                         for (k = 0; k < s->mc_hosts->used; k++) {
18471                                 data_string *ds = (data_string *)s->mc_hosts->data[k];
18472 -                               
18473 +
18474                                 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
18475 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
18476 -                                                       "connection to host failed:", 
18477 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
18478 +                                                       "connection to host failed:",
18479                                                         ds->value);
18480 -                                       
18481 +
18482                                         return HANDLER_ERROR;
18483                                 }
18484                         }
18485  #else
18486 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
18487 +                       log_error_write(srv, __FILE__, __LINE__, "s",
18488                                         "memcache support is not compiled in but cml.memcache-hosts is set, aborting");
18489                         return HANDLER_ERROR;
18490  #endif
18491                 }
18492         }
18493 -       
18494 +
18495         return HANDLER_GO_ON;
18496  }
18497  
18498 -#define PATCH(x) \
18499 -       p->conf.x = s->x;
18500  static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p) {
18501         size_t i, j;
18502         plugin_config *s = p->config_storage[0];
18503 -       
18504 -       PATCH(ext);
18505 +
18506 +       PATCH_OPTION(ext);
18507  #if defined(HAVE_MEMCACHE_H)
18508 -       PATCH(mc);
18509 +       PATCH_OPTION(mc);
18510  #endif
18511 -       PATCH(mc_namespace);
18512 -       PATCH(power_magnet);
18513 -       
18514 +       PATCH_OPTION(mc_namespace);
18515 +       PATCH_OPTION(power_magnet);
18516 +
18517         /* skip the first, the global context */
18518         for (i = 1; i < srv->config_context->used; i++) {
18519                 data_config *dc = (data_config *)srv->config_context->data[i];
18520                 s = p->config_storage[i];
18521 -               
18522 +
18523                 /* condition didn't match */
18524                 if (!config_check_cond(srv, con, dc)) continue;
18525 -               
18526 +
18527                 /* merge config */
18528                 for (j = 0; j < dc->value->used; j++) {
18529                         data_unset *du = dc->value->data[j];
18530 -                       
18531 +
18532                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.extension"))) {
18533 -                               PATCH(ext);
18534 +                               PATCH_OPTION(ext);
18535                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-hosts"))) {
18536  #if defined(HAVE_MEMCACHE_H)
18537 -                               PATCH(mc);
18538 +                               PATCH_OPTION(mc);
18539  #endif
18540                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-namespace"))) {
18541 -                               PATCH(mc_namespace);
18542 +                               PATCH_OPTION(mc_namespace);
18543                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.power-magnet"))) {
18544 -                               PATCH(power_magnet);
18545 +                               PATCH_OPTION(power_magnet);
18546                         }
18547                 }
18548         }
18549 -       
18550 +
18551         return 0;
18552  }
18553 -#undef PATCH
18554  
18555  int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
18556         buffer *b;
18557 @@ -187,57 +183,57 @@
18558         b = p->baseurl;
18559         buffer_copy_string_buffer(b, con->uri.path);
18560         for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
18561 -       
18562 +
18563         if (*c == '/') {
18564                 b->used = c - b->ptr + 2;
18565                 *(c+1) = '\0';
18566         }
18567 -       
18568 +
18569         b = p->basedir;
18570         buffer_copy_string_buffer(b, con->physical.path);
18571         for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
18572 -       
18573 +
18574         if (*c == '/') {
18575                 b->used = c - b->ptr + 2;
18576                 *(c+1) = '\0';
18577         }
18578 -       
18579 +
18580  
18581         /* prepare variables
18582          *   - cookie-based
18583          *   - get-param-based
18584          */
18585 -       
18586 +
18587         return cache_parse_lua(srv, con, p, cml_file);
18588 -       
18589 +
18590  }
18591  
18592  URIHANDLER_FUNC(mod_cml_power_magnet) {
18593         plugin_data *p = p_d;
18594 -       
18595 +
18596         mod_cml_patch_connection(srv, con, p);
18597 -       
18598 +
18599         buffer_reset(p->basedir);
18600         buffer_reset(p->baseurl);
18601         buffer_reset(p->trigger_handler);
18602  
18603         if (buffer_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
18604 -       
18605 -       /* 
18606 +
18607 +       /*
18608          * power-magnet:
18609          * cml.power-magnet = server.docroot + "/rewrite.cml"
18610          *
18611          * is called on EACH request, take the original REQUEST_URI and modifies the
18612 -        * request header as neccesary. 
18613 +        * request header as neccesary.
18614          *
18615          * First use:
18616          * if file_exists("/maintainance.html") {
18617          *   output_include = ( "/maintainance.html" )
18618 -        *   return CACHE_HIT 
18619 +        *   return CACHE_HIT
18620          * }
18621          *
18622          * as we only want to rewrite HTML like requests we should cover it in a conditional
18623 -        * 
18624 +        *
18625          * */
18626  
18627         switch(cache_call_lua(srv, con, p, p->conf.power_magnet)) {
18628 @@ -266,20 +262,20 @@
18629  
18630  URIHANDLER_FUNC(mod_cml_is_handled) {
18631         plugin_data *p = p_d;
18632 -       
18633 +
18634         if (buffer_is_empty(con->physical.path)) return HANDLER_ERROR;
18635 -       
18636 +
18637         mod_cml_patch_connection(srv, con, p);
18638 -       
18639 +
18640         buffer_reset(p->basedir);
18641         buffer_reset(p->baseurl);
18642         buffer_reset(p->trigger_handler);
18643  
18644         if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON;
18645 -       
18646 +
18647         if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, p->conf.ext->used - 1)) {
18648                 return HANDLER_GO_ON;
18649 -       } 
18650 +       }
18651  
18652         switch(cache_call_lua(srv, con, p, con->physical.path)) {
18653         case -1:
18654 @@ -311,15 +307,15 @@
18655  int mod_cml_plugin_init(plugin *p) {
18656         p->version     = LIGHTTPD_VERSION_ID;
18657         p->name        = buffer_init_string("cache");
18658 -       
18659 +
18660         p->init        = mod_cml_init;
18661         p->cleanup     = mod_cml_free;
18662         p->set_defaults  = mod_cml_set_defaults;
18663 -       
18664 +
18665         p->handle_subrequest_start = mod_cml_is_handled;
18666         p->handle_physical         = mod_cml_power_magnet;
18667 -       
18668 +
18669         p->data        = NULL;
18670 -       
18671 +
18672         return 0;
18673  }
18674 --- ../lighttpd-1.4.11/src/mod_cml.h    2006-01-30 13:51:35.000000000 +0200
18675 +++ lighttpd-1.4.12/src/mod_cml.h       2006-07-16 00:26:03.000000000 +0300
18676 @@ -16,10 +16,10 @@
18677  
18678  typedef struct {
18679         buffer *ext;
18680 -       
18681 +
18682         array  *mc_hosts;
18683         buffer *mc_namespace;
18684 -#if defined(HAVE_MEMCACHE_H) 
18685 +#if defined(HAVE_MEMCACHE_H)
18686         struct memcache *mc;
18687  #endif
18688         buffer *power_magnet;
18689 @@ -27,15 +27,15 @@
18690  
18691  typedef struct {
18692         PLUGIN_DATA;
18693 -       
18694 +
18695         buffer *basedir;
18696         buffer *baseurl;
18697 -       
18698 +
18699         buffer *trigger_handler;
18700 -       
18701 +
18702         plugin_config **config_storage;
18703 -       
18704 -       plugin_config conf; 
18705 +
18706 +       plugin_config conf;
18707  } plugin_data;
18708  
18709  int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn);
18710 --- ../lighttpd-1.4.11/src/mod_cml_funcs.c      2005-11-17 16:15:08.000000000 +0200
18711 +++ lighttpd-1.4.12/src/mod_cml_funcs.c 2006-07-16 00:26:04.000000000 +0300
18712 @@ -4,8 +4,7 @@
18713  #include <stdlib.h>
18714  #include <string.h>
18715  #include <errno.h>
18716 -#include <unistd.h>
18717 -#include <dirent.h>
18718 +
18719  #include <stdio.h>
18720  
18721  #include "buffer.h"
18722 @@ -13,6 +12,7 @@
18723  #include "log.h"
18724  #include "plugin.h"
18725  #include "response.h"
18726 +#include "sys-files.h"
18727  
18728  #include "mod_cml.h"
18729  #include "mod_cml_funcs.h"
18730 @@ -30,7 +30,7 @@
18731  #ifdef USE_OPENSSL
18732  #define IN const
18733  #else
18734 -#define IN 
18735 +#define IN
18736  #endif
18737  #define OUT
18738  
18739 @@ -42,29 +42,29 @@
18740         buffer b;
18741         char hex[33];
18742         int n = lua_gettop(L);
18743 -       
18744 +
18745         b.ptr = hex;
18746         b.used = 0;
18747         b.size = sizeof(hex);
18748 -       
18749 +
18750         if (n != 1) {
18751                 lua_pushstring(L, "md5: expected one argument");
18752                 lua_error(L);
18753         }
18754 -       
18755 +
18756         if (!lua_isstring(L, 1)) {
18757                 lua_pushstring(L, "md5: argument has to be a string");
18758                 lua_error(L);
18759         }
18760 -       
18761 +
18762         MD5_Init(&Md5Ctx);
18763         MD5_Update(&Md5Ctx, (unsigned char *)lua_tostring(L, 1), lua_strlen(L, 1));
18764         MD5_Final(HA1, &Md5Ctx);
18765 -       
18766 +
18767         buffer_copy_string_hex(&b, (char *)HA1, 16);
18768 -       
18769 +
18770         lua_pushstring(L, b.ptr);
18771 -       
18772 +
18773         return 1;
18774  }
18775  
18776 @@ -72,37 +72,37 @@
18777  int f_file_mtime(lua_State *L) {
18778         struct stat st;
18779         int n = lua_gettop(L);
18780 -       
18781 +
18782         if (n != 1) {
18783                 lua_pushstring(L, "file_mtime: expected one argument");
18784                 lua_error(L);
18785         }
18786 -       
18787 +
18788         if (!lua_isstring(L, 1)) {
18789                 lua_pushstring(L, "file_mtime: argument has to be a string");
18790                 lua_error(L);
18791         }
18792 -       
18793 +
18794         if (-1 == stat(lua_tostring(L, 1), &st)) {
18795                 lua_pushnil(L);
18796                 return 1;
18797         }
18798 -       
18799 +
18800         lua_pushnumber(L, st.st_mtime);
18801 -       
18802 +
18803         return 1;
18804  }
18805 -
18806 +#ifndef _WIN32
18807  int f_dir_files_iter(lua_State *L) {
18808         DIR *d;
18809         struct dirent *de;
18810 -       
18811 +
18812         d = lua_touserdata(L, lua_upvalueindex(1));
18813 -       
18814 +
18815         if (NULL == (de = readdir(d))) {
18816                 /* EOF */
18817                 closedir(d);
18818 -               
18819 +
18820                 return 0;
18821         } else {
18822                 lua_pushstring(L, de->d_name);
18823 @@ -113,75 +113,75 @@
18824  int f_dir_files(lua_State *L) {
18825         DIR *d;
18826         int n = lua_gettop(L);
18827 -       
18828 +
18829         if (n != 1) {
18830                 lua_pushstring(L, "dir_files: expected one argument");
18831                 lua_error(L);
18832         }
18833 -       
18834 +
18835         if (!lua_isstring(L, 1)) {
18836                 lua_pushstring(L, "dir_files: argument has to be a string");
18837                 lua_error(L);
18838         }
18839 -       
18840 -       /* check if there is a valid DIR handle on the stack */ 
18841 +
18842 +       /* check if there is a valid DIR handle on the stack */
18843         if (NULL == (d = opendir(lua_tostring(L, 1)))) {
18844                 lua_pushnil(L);
18845                 return 1;
18846         }
18847 -       
18848 +
18849         /* push d into registry */
18850         lua_pushlightuserdata(L, d);
18851         lua_pushcclosure(L, f_dir_files_iter, 1);
18852 -       
18853 +
18854         return 1;
18855  }
18856 -
18857 +#endif
18858  int f_file_isreg(lua_State *L) {
18859         struct stat st;
18860         int n = lua_gettop(L);
18861 -       
18862 +
18863         if (n != 1) {
18864                 lua_pushstring(L, "file_isreg: expected one argument");
18865                 lua_error(L);
18866         }
18867 -       
18868 +
18869         if (!lua_isstring(L, 1)) {
18870                 lua_pushstring(L, "file_isreg: argument has to be a string");
18871                 lua_error(L);
18872         }
18873 -       
18874 +
18875         if (-1 == stat(lua_tostring(L, 1), &st)) {
18876                 lua_pushnil(L);
18877                 return 1;
18878         }
18879 -       
18880 +
18881         lua_pushnumber(L, S_ISREG(st.st_mode));
18882 -       
18883 +
18884         return 1;
18885  }
18886  
18887  int f_file_isdir(lua_State *L) {
18888         struct stat st;
18889         int n = lua_gettop(L);
18890 -       
18891 +
18892         if (n != 1) {
18893                 lua_pushstring(L, "file_isreg: expected one argument");
18894                 lua_error(L);
18895         }
18896 -       
18897 +
18898         if (!lua_isstring(L, 1)) {
18899                 lua_pushstring(L, "file_isreg: argument has to be a string");
18900                 lua_error(L);
18901         }
18902 -       
18903 +
18904         if (-1 == stat(lua_tostring(L, 1), &st)) {
18905                 lua_pushnil(L);
18906                 return 1;
18907         }
18908 -       
18909 +
18910         lua_pushnumber(L, S_ISDIR(st.st_mode));
18911 -       
18912 +
18913         return 1;
18914  }
18915  
18916 @@ -192,33 +192,33 @@
18917         char *r;
18918         int n = lua_gettop(L);
18919         struct memcache *mc;
18920 -       
18921 +
18922         if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18923                 lua_pushstring(L, "where is my userdata ?");
18924                 lua_error(L);
18925         }
18926 -       
18927 +
18928         mc = lua_touserdata(L, lua_upvalueindex(1));
18929 -       
18930 +
18931         if (n != 1) {
18932                 lua_pushstring(L, "expected one argument");
18933                 lua_error(L);
18934         }
18935 -       
18936 +
18937         if (!lua_isstring(L, 1)) {
18938                 lua_pushstring(L, "argument has to be a string");
18939                 lua_error(L);
18940         }
18941 -       
18942 -       if (NULL == (r = mc_aget(mc, 
18943 +
18944 +       if (NULL == (r = mc_aget(mc,
18945                                  lua_tostring(L, 1), lua_strlen(L, 1)))) {
18946 -                               
18947 +
18948                 lua_pushboolean(L, 0);
18949                 return 1;
18950         }
18951 -       
18952 +
18953         free(r);
18954 -       
18955 +
18956         lua_pushboolean(L, 1);
18957         return 1;
18958  }
18959 @@ -226,74 +226,74 @@
18960  int f_memcache_get_string(lua_State *L) {
18961         char *r;
18962         int n = lua_gettop(L);
18963 -       
18964 +
18965         struct memcache *mc;
18966 -       
18967 +
18968         if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18969                 lua_pushstring(L, "where is my userdata ?");
18970                 lua_error(L);
18971         }
18972 -       
18973 +
18974         mc = lua_touserdata(L, lua_upvalueindex(1));
18975 -       
18976 -       
18977 +
18978 +
18979         if (n != 1) {
18980                 lua_pushstring(L, "expected one argument");
18981                 lua_error(L);
18982         }
18983 -       
18984 +
18985         if (!lua_isstring(L, 1)) {
18986                 lua_pushstring(L, "argument has to be a string");
18987                 lua_error(L);
18988         }
18989 -       
18990 -       if (NULL == (r = mc_aget(mc, 
18991 +
18992 +       if (NULL == (r = mc_aget(mc,
18993                                  lua_tostring(L, 1), lua_strlen(L, 1)))) {
18994                 lua_pushnil(L);
18995                 return 1;
18996         }
18997 -       
18998 +
18999         lua_pushstring(L, r);
19000 -       
19001 +
19002         free(r);
19003 -       
19004 +
19005         return 1;
19006  }
19007  
19008  int f_memcache_get_long(lua_State *L) {
19009         char *r;
19010         int n = lua_gettop(L);
19011 -       
19012 +
19013         struct memcache *mc;
19014 -       
19015 +
19016         if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
19017                 lua_pushstring(L, "where is my userdata ?");
19018                 lua_error(L);
19019         }
19020 -       
19021 +
19022         mc = lua_touserdata(L, lua_upvalueindex(1));
19023 -       
19024 -       
19025 +
19026 +
19027         if (n != 1) {
19028                 lua_pushstring(L, "expected one argument");
19029                 lua_error(L);
19030         }
19031 -       
19032 +
19033         if (!lua_isstring(L, 1)) {
19034                 lua_pushstring(L, "argument has to be a string");
19035                 lua_error(L);
19036         }
19037 -       
19038 -       if (NULL == (r = mc_aget(mc, 
19039 +
19040 +       if (NULL == (r = mc_aget(mc,
19041                                  lua_tostring(L, 1), lua_strlen(L, 1)))) {
19042                 lua_pushnil(L);
19043                 return 1;
19044         }
19045 -       
19046 +
19047         lua_pushnumber(L, strtol(r, NULL, 10));
19048 -       
19049 +
19050         free(r);
19051 -       
19052 +
19053         return 1;
19054  }
19055  #endif
19056 --- ../lighttpd-1.4.11/src/mod_cml_lua.c        2006-01-30 13:56:40.000000000 +0200
19057 +++ lighttpd-1.4.12/src/mod_cml_lua.c   2006-07-16 00:26:04.000000000 +0300
19058 @@ -23,7 +23,7 @@
19059  #ifdef USE_OPENSSL
19060  #define IN const
19061  #else
19062 -#define IN 
19063 +#define IN
19064  #endif
19065  #define OUT
19066  
19067 @@ -31,6 +31,7 @@
19068  
19069  #include <lua.h>
19070  #include <lualib.h>
19071 +#include <lauxlib.h>
19072  
19073  typedef struct {
19074         stream st;
19075 @@ -39,11 +40,11 @@
19076  
19077  static const char * load_file(lua_State *L, void *data, size_t *size) {
19078         readme *rm = data;
19079 -       
19080 +
19081         UNUSED(L);
19082 -       
19083 +
19084         if (rm->done) return 0;
19085 -       
19086 +
19087         *size = rm->st.size;
19088         rm->done = 1;
19089         return rm->st.start;
19090 @@ -51,47 +52,47 @@
19091  
19092  static int lua_to_c_get_string(lua_State *L, const char *varname, buffer *b) {
19093         int curelem;
19094 -       
19095 +
19096         lua_pushstring(L, varname);
19097 -       
19098 +
19099         curelem = lua_gettop(L);
19100         lua_gettable(L, LUA_GLOBALSINDEX);
19101 -       
19102 +
19103         /* it should be a table */
19104         if (!lua_isstring(L, curelem)) {
19105                 lua_settop(L, curelem - 1);
19106 -               
19107 +
19108                 return -1;
19109         }
19110 -       
19111 +
19112         buffer_copy_string(b, lua_tostring(L, curelem));
19113 -       
19114 +
19115         lua_pop(L, 1);
19116 -       
19117 +
19118         assert(curelem - 1 == lua_gettop(L));
19119 -       
19120 +
19121         return 0;
19122  }
19123  
19124  static int lua_to_c_is_table(lua_State *L, const char *varname) {
19125         int curelem;
19126 -       
19127 +
19128         lua_pushstring(L, varname);
19129 -       
19130 +
19131         curelem = lua_gettop(L);
19132         lua_gettable(L, LUA_GLOBALSINDEX);
19133 -       
19134 +
19135         /* it should be a table */
19136         if (!lua_istable(L, curelem)) {
19137                 lua_settop(L, curelem - 1);
19138 -               
19139 +
19140                 return 0;
19141         }
19142 -       
19143 +
19144         lua_settop(L, curelem - 1);
19145 -       
19146 +
19147         assert(curelem - 1 == lua_gettop(L));
19148 -       
19149 +
19150         return 1;
19151  }
19152  
19153 @@ -99,7 +100,7 @@
19154         lua_pushlstring(L, key, key_len);
19155         lua_pushlstring(L, val, val_len);
19156         lua_settable(L, tbl);
19157 -       
19158 +
19159         return 0;
19160  }
19161  
19162 @@ -108,21 +109,21 @@
19163         size_t is_key = 1;
19164         size_t i;
19165         char *key = NULL, *val = NULL;
19166 -       
19167 +
19168         key = qrystr->ptr;
19169 -       
19170 +
19171         /* we need the \0 */
19172         for (i = 0; i < qrystr->used; i++) {
19173                 switch(qrystr->ptr[i]) {
19174                 case '=':
19175                         if (is_key) {
19176                                 val = qrystr->ptr + i + 1;
19177 -                               
19178 +
19179                                 qrystr->ptr[i] = '\0';
19180 -                               
19181 +
19182                                 is_key = 0;
19183                         }
19184 -                       
19185 +
19186                         break;
19187                 case '&':
19188                 case '\0': /* fin symbol */
19189 @@ -131,19 +132,19 @@
19190  
19191                                 /* terminate the value */
19192                                 qrystr->ptr[i] = '\0';
19193 -                               
19194 -                               c_to_lua_push(L, tbl, 
19195 +
19196 +                               c_to_lua_push(L, tbl,
19197                                               key, strlen(key),
19198                                               val, strlen(val));
19199                         }
19200 -                       
19201 +
19202                         key = qrystr->ptr + i + 1;
19203                         val = NULL;
19204                         is_key = 1;
19205                         break;
19206                 }
19207         }
19208 -       
19209 +
19210         return 0;
19211  }
19212  #if 0
19213 @@ -151,21 +152,21 @@
19214         data_unset *d;
19215  
19216         UNUSED(srv);
19217 -       
19218 +
19219         if (NULL != (d = array_get_element(con->request.headers, "Cookie"))) {
19220                 data_string *ds = (data_string *)d;
19221                 size_t key = 0, value = 0;
19222                 size_t is_key = 1, is_sid = 0;
19223                 size_t i;
19224 -               
19225 +
19226                 /* found COOKIE */
19227                 if (!DATA_IS_STRING(d)) return -1;
19228                 if (ds->value->used == 0) return -1;
19229 -                       
19230 +
19231                 if (ds->value->ptr[0] == '\0' ||
19232                     ds->value->ptr[0] == '=' ||
19233                     ds->value->ptr[0] == ';') return -1;
19234 -               
19235 +
19236                 buffer_reset(p->session_id);
19237                 for (i = 0; i < ds->value->used; i++) {
19238                         switch(ds->value->ptr[i]) {
19239 @@ -176,16 +177,16 @@
19240                                                 is_sid = 1;
19241                                         }
19242                                         value = i + 1;
19243 -                               
19244 +
19245                                         is_key = 0;
19246                                 }
19247 -                               
19248 +
19249                                 break;
19250                         case ';':
19251                                 if (is_sid) {
19252                                         buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value);
19253                                 }
19254 -                               
19255 +
19256                                 is_sid = 0;
19257                                 key = i + 1;
19258                                 value = 0;
19259 @@ -204,48 +205,43 @@
19260                         }
19261                 }
19262         }
19263 -       
19264 +
19265         return 0;
19266  }
19267  #endif
19268  
19269  int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
19270 -       lua_State *L; 
19271 +       lua_State *L;
19272         readme rm;
19273         int ret = -1;
19274         buffer *b = buffer_init();
19275         int header_tbl = 0;
19276 -       
19277 +
19278         rm.done = 0;
19279         stream_open(&rm.st, fn);
19280 -       
19281 +
19282         /* push the lua file to the interpreter and see what happends */
19283 -       L = lua_open();
19284 -       
19285 -       luaopen_base(L);
19286 -       luaopen_table(L);
19287 -       luaopen_string(L);
19288 -       luaopen_math(L);
19289 -       luaopen_io(L);
19290 -       
19291 +       L = luaL_newstate();
19292 +       luaL_openlibs(L);
19293 +
19294         /* register functions */
19295         lua_register(L, "md5", f_crypto_md5);
19296         lua_register(L, "file_mtime", f_file_mtime);
19297         lua_register(L, "file_isreg", f_file_isreg);
19298         lua_register(L, "file_isdir", f_file_isreg);
19299         lua_register(L, "dir_files", f_dir_files);
19300 -       
19301 +
19302  #ifdef HAVE_MEMCACHE_H
19303         lua_pushliteral(L, "memcache_get_long");
19304         lua_pushlightuserdata(L, p->conf.mc);
19305         lua_pushcclosure(L, f_memcache_get_long, 1);
19306         lua_settable(L, LUA_GLOBALSINDEX);
19307 -       
19308 +
19309         lua_pushliteral(L, "memcache_get_string");
19310         lua_pushlightuserdata(L, p->conf.mc);
19311         lua_pushcclosure(L, f_memcache_get_string, 1);
19312         lua_settable(L, LUA_GLOBALSINDEX);
19313 -       
19314 +
19315         lua_pushliteral(L, "memcache_exists");
19316         lua_pushlightuserdata(L, p->conf.mc);
19317         lua_pushcclosure(L, f_memcache_exists, 1);
19318 @@ -255,11 +251,11 @@
19319         lua_pushliteral(L, "request");
19320         lua_newtable(L);
19321         lua_settable(L, LUA_GLOBALSINDEX);
19322 -       
19323 +
19324         lua_pushliteral(L, "request");
19325         header_tbl = lua_gettop(L);
19326         lua_gettable(L, LUA_GLOBALSINDEX);
19327 -       
19328 +
19329         c_to_lua_push(L, header_tbl, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
19330         c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
19331         c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
19332 @@ -267,84 +263,84 @@
19333         if (!buffer_is_empty(con->request.pathinfo)) {
19334                 c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
19335         }
19336 -       
19337 +
19338         c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir));
19339         c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl));
19340 -       
19341 +
19342         /* register GET parameter */
19343         lua_pushliteral(L, "get");
19344         lua_newtable(L);
19345         lua_settable(L, LUA_GLOBALSINDEX);
19346 -       
19347 +
19348         lua_pushliteral(L, "get");
19349         header_tbl = lua_gettop(L);
19350         lua_gettable(L, LUA_GLOBALSINDEX);
19351 -       
19352 +
19353         buffer_copy_string_buffer(b, con->uri.query);
19354         cache_export_get_params(L, header_tbl, b);
19355         buffer_reset(b);
19356  
19357 -       /* 2 default constants */       
19358 +       /* 2 default constants */
19359         lua_pushliteral(L, "CACHE_HIT");
19360         lua_pushboolean(L, 0);
19361         lua_settable(L, LUA_GLOBALSINDEX);
19362 -       
19363 +
19364         lua_pushliteral(L, "CACHE_MISS");
19365         lua_pushboolean(L, 1);
19366         lua_settable(L, LUA_GLOBALSINDEX);
19367 -       
19368 +
19369         /* load lua program */
19370         if (lua_load(L, load_file, &rm, fn->ptr) || lua_pcall(L,0,1,0)) {
19371                 log_error_write(srv, __FILE__, __LINE__, "s",
19372                                 lua_tostring(L,-1));
19373 -               
19374 +
19375                 goto error;
19376         }
19377 -       
19378 +
19379         /* get return value */
19380         ret = (int)lua_tonumber(L, -1);
19381         lua_pop(L, 1);
19382 -       
19383 -       /* fetch the data from lua */ 
19384 +
19385 +       /* fetch the data from lua */
19386         lua_to_c_get_string(L, "trigger_handler", p->trigger_handler);
19387 -       
19388 +
19389         if (0 == lua_to_c_get_string(L, "output_contenttype", b)) {
19390                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b));
19391         }
19392 -       
19393 +
19394         if (ret == 0) {
19395                 /* up to now it is a cache-hit, check if all files exist */
19396 -               
19397 +
19398                 int curelem;
19399                 time_t mtime = 0;
19400 -       
19401 +
19402                 if (!lua_to_c_is_table(L, "output_include")) {
19403                         log_error_write(srv, __FILE__, __LINE__, "s",
19404                                 "output_include is missing or not a table");
19405                         ret = -1;
19406 -               
19407 +
19408                         goto error;
19409                 }
19410 -               
19411 +
19412                 lua_pushstring(L, "output_include");
19413 -               
19414 +
19415                 curelem = lua_gettop(L);
19416                 lua_gettable(L, LUA_GLOBALSINDEX);
19417  
19418                 /* HOW-TO build a etag ?
19419 -                * as we don't just have one file we have to take the stat() 
19420 +                * as we don't just have one file we have to take the stat()
19421                  * from all base files, merge them and build the etag from
19422                  * it later.
19423 -                * 
19424 +                *
19425                  * The mtime of the content is the mtime of the freshest base file
19426 -                * 
19427 +                *
19428                  * */
19429 -               
19430 +
19431                 lua_pushnil(L);  /* first key */
19432                 while (lua_next(L, curelem) != 0) {
19433                         stat_cache_entry *sce = NULL;
19434                         /* key' is at index -2 and value' at index -1 */
19435 -                       
19436 +
19437                         if (lua_isstring(L, -1)) {
19438                                 const char *s = lua_tostring(L, -1);
19439  
19440 @@ -364,18 +360,18 @@
19441                                                 /* a file is missing, call the handler to generate it */
19442                                                 if (!buffer_is_empty(p->trigger_handler)) {
19443                                                         ret = 1; /* cache-miss */
19444 -                                                       
19445 +
19446                                                         log_error_write(srv, __FILE__, __LINE__, "s",
19447                                                                         "a file is missing, calling handler");
19448 -                                                       
19449 +
19450                                                         break;
19451                                                 } else {
19452                                                         /* handler not set -> 500 */
19453                                                         ret = -1;
19454 -                                                       
19455 +
19456                                                         log_error_write(srv, __FILE__, __LINE__, "s",
19457                                                                         "a file missing and no handler set");
19458 -                                                       
19459 +
19460                                                         break;
19461                                                 }
19462                                                 break;
19463 @@ -393,12 +389,12 @@
19464                                                 "not a string");
19465                                 break;
19466                         }
19467 -               
19468 +
19469                         lua_pop(L, 1);  /* removes value'; keeps key' for next iteration */
19470                 }
19471 -               
19472 +
19473                 lua_settop(L, curelem - 1);
19474 -               
19475 +
19476                 if (ret == 0) {
19477                         data_string *ds;
19478                         char timebuf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
19479 @@ -410,9 +406,9 @@
19480  
19481                         /* no Last-Modified specified */
19482                         if ((mtime) && (NULL == ds)) {
19483 -               
19484 +
19485                                 strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime));
19486 -                               
19487 +
19488                                 response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), timebuf, sizeof(timebuf) - 1);
19489  
19490  
19491 @@ -428,9 +424,9 @@
19492                                 tbuf.used = 0;
19493                                 tbuf.ptr = NULL;
19494                         }
19495 -                       
19496 +
19497                         if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, &tbuf)) {
19498 -                               /* ok, the client already has our content, 
19499 +                               /* ok, the client already has our content,
19500                                  * no need to send it again */
19501  
19502                                 chunkqueue_reset(con->write_queue);
19503 @@ -440,24 +436,24 @@
19504                         chunkqueue_reset(con->write_queue);
19505                 }
19506         }
19507 -       
19508 +
19509         if (ret == 1 && !buffer_is_empty(p->trigger_handler)) {
19510                 /* cache-miss */
19511                 buffer_copy_string_buffer(con->uri.path, p->baseurl);
19512                 buffer_append_string_buffer(con->uri.path, p->trigger_handler);
19513 -       
19514 +
19515                 buffer_copy_string_buffer(con->physical.path, p->basedir);
19516                 buffer_append_string_buffer(con->physical.path, p->trigger_handler);
19517 -               
19518 +
19519                 chunkqueue_reset(con->write_queue);
19520         }
19521 -       
19522 +
19523  error:
19524         lua_close(L);
19525 -       
19526 +
19527         stream_close(&rm.st);
19528         buffer_free(b);
19529 -       
19530 +
19531         return ret /* cache-error */;
19532  }
19533  #else
19534 --- ../lighttpd-1.4.11/src/mod_compress.c       2005-11-18 13:49:14.000000000 +0200
19535 +++ lighttpd-1.4.12/src/mod_compress.c  2006-07-16 00:26:04.000000000 +0300
19536 @@ -2,7 +2,6 @@
19537  #include <sys/stat.h>
19538  
19539  #include <fcntl.h>
19540 -#include <unistd.h>
19541  #include <ctype.h>
19542  #include <stdlib.h>
19543  #include <string.h>
19544 @@ -14,6 +13,7 @@
19545  #include "buffer.h"
19546  #include "response.h"
19547  #include "stat_cache.h"
19548 +#include "http_chunk.h"
19549  
19550  #include "plugin.h"
19551  
19552 @@ -33,6 +33,7 @@
19553  #endif
19554  
19555  #include "sys-mmap.h"
19556 +#include "sys-files.h"
19557  
19558  /* request: accept-encoding */
19559  #define HTTP_ACCEPT_ENCODING_IDENTITY BV(0)
19560 @@ -55,97 +56,127 @@
19561         PLUGIN_DATA;
19562         buffer *ofn;
19563         buffer *b;
19564 -       
19565 +
19566         plugin_config **config_storage;
19567 -       plugin_config conf; 
19568 +       plugin_config conf;
19569  } plugin_data;
19570  
19571  INIT_FUNC(mod_compress_init) {
19572         plugin_data *p;
19573 -       
19574 +
19575         p = calloc(1, sizeof(*p));
19576 -       
19577 +
19578         p->ofn = buffer_init();
19579         p->b = buffer_init();
19580 -       
19581 +
19582         return p;
19583  }
19584  
19585  FREE_FUNC(mod_compress_free) {
19586         plugin_data *p = p_d;
19587 -       
19588 +
19589         UNUSED(srv);
19590  
19591         if (!p) return HANDLER_GO_ON;
19592 -       
19593 +
19594         buffer_free(p->ofn);
19595         buffer_free(p->b);
19596 -       
19597 +
19598         if (p->config_storage) {
19599                 size_t i;
19600                 for (i = 0; i < srv->config_context->used; i++) {
19601                         plugin_config *s = p->config_storage[i];
19602  
19603                         if (!s) continue;
19604 -                       
19605 +
19606                         array_free(s->compress);
19607                         buffer_free(s->compress_cache_dir);
19608 -                       
19609 +
19610                         free(s);
19611                 }
19612                 free(p->config_storage);
19613         }
19614 -       
19615 -       
19616 +
19617 +
19618         free(p);
19619 -       
19620 +
19621         return HANDLER_GO_ON;
19622  }
19623  
19624 +void mkdir_recursive(const char *dir) {
19625 +
19626 +       char dir_copy[256];
19627 +       char *p = dir_copy;
19628 +
19629 +       if (!dir || !dir[0])
19630 +               return;
19631 +
19632 +       strncpy(dir_copy, dir, sizeof(dir_copy) / sizeof(dir_copy[0]));
19633 +
19634 +       while ((p = strchr(p + 1, '/')) != NULL) {
19635 +
19636 +               *p = '\0';
19637 +               if ((mkdir(dir_copy, 0700) != 0) && (errno != EEXIST))
19638 +                       return;
19639 +
19640 +               *p++ = '/';
19641 +       }
19642 +
19643 +       mkdir(dir, 0700);
19644 +}
19645 +
19646  SETDEFAULTS_FUNC(mod_compress_setdefaults) {
19647         plugin_data *p = p_d;
19648         size_t i = 0;
19649 -       
19650 -       config_values_t cv[] = { 
19651 +
19652 +       config_values_t cv[] = {
19653                 { "compress.cache-dir",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
19654                 { "compress.filetype",              NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
19655                 { "compress.max-filesize",          NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
19656                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
19657         };
19658 -       
19659 +
19660         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
19661 -       
19662 +
19663         for (i = 0; i < srv->config_context->used; i++) {
19664                 plugin_config *s;
19665 -               
19666 +
19667                 s = calloc(1, sizeof(plugin_config));
19668                 s->compress_cache_dir = buffer_init();
19669                 s->compress = array_init();
19670                 s->compress_max_filesize = 0;
19671 -               
19672 +
19673                 cv[0].destination = s->compress_cache_dir;
19674                 cv[1].destination = s->compress;
19675                 cv[2].destination = &(s->compress_max_filesize);
19676 -               
19677 +
19678                 p->config_storage[i] = s;
19679 -       
19680 +
19681                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
19682                         return HANDLER_ERROR;
19683                 }
19684 -               
19685 +
19686                 if (!buffer_is_empty(s->compress_cache_dir)) {
19687                         struct stat st;
19688                         if (0 != stat(s->compress_cache_dir->ptr, &st)) {
19689 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir", 
19690 +
19691 +                               log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, attempting to create",
19692                                                 s->compress_cache_dir, strerror(errno));
19693 -                               
19694 -                               return HANDLER_ERROR;
19695 +                               mkdir_recursive(s->compress_cache_dir->ptr);
19696 +
19697 +                               if (0 != stat(s->compress_cache_dir->ptr, &st)) {
19698 +
19699 +                                       log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, create failed",
19700 +                                                                       s->compress_cache_dir, strerror(errno));
19701 +
19702 +                                       return HANDLER_ERROR;
19703 +                               }
19704                         }
19705                 }
19706         }
19707 -       
19708 +
19709         return HANDLER_GO_ON;
19710 -       
19711 +
19712  }
19713  
19714  #ifdef USE_ZLIB
19715 @@ -153,32 +184,32 @@
19716         unsigned char *c;
19717         unsigned long crc;
19718         z_stream z;
19719 -       
19720 +
19721         UNUSED(srv);
19722         UNUSED(con);
19723  
19724         z.zalloc = Z_NULL;
19725         z.zfree = Z_NULL;
19726         z.opaque = Z_NULL;
19727 -       
19728 -       if (Z_OK != deflateInit2(&z, 
19729 +
19730 +       if (Z_OK != deflateInit2(&z,
19731                                  Z_DEFAULT_COMPRESSION,
19732 -                                Z_DEFLATED, 
19733 +                                Z_DEFLATED,
19734                                  -MAX_WBITS,  /* supress zlib-header */
19735                                  8,
19736                                  Z_DEFAULT_STRATEGY)) {
19737                 return -1;
19738         }
19739 -               
19740 +
19741         z.next_in = (unsigned char *)start;
19742         z.avail_in = st_size;
19743         z.total_in = 0;
19744 -               
19745 -                       
19746 +
19747 +
19748         buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12 + 18);
19749 -               
19750 +
19751         /* write gzip header */
19752 -               
19753 +
19754         c = (unsigned char *)p->b->ptr;
19755         c[0] = 0x1f;
19756         c[1] = 0x8b;
19757 @@ -190,24 +221,24 @@
19758         c[7] = (mtime >> 24) & 0xff;
19759         c[8] = 0x00; /* extra flags */
19760         c[9] = 0x03; /* UNIX */
19761 -       
19762 +
19763         p->b->used = 10;
19764         z.next_out = (unsigned char *)p->b->ptr + p->b->used;
19765         z.avail_out = p->b->size - p->b->used - 8;
19766         z.total_out = 0;
19767 -       
19768 +
19769         if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
19770                 deflateEnd(&z);
19771                 return -1;
19772         }
19773 -       
19774 +
19775         /* trailer */
19776         p->b->used += z.total_out;
19777 -       
19778 +
19779         crc = generate_crc32c(start, st_size);
19780 -               
19781 +
19782         c = (unsigned char *)p->b->ptr + p->b->used;
19783 -               
19784 +
19785         c[0] = (crc >>  0) & 0xff;
19786         c[1] = (crc >>  8) & 0xff;
19787         c[2] = (crc >> 16) & 0xff;
19788 @@ -221,51 +252,51 @@
19789         if (Z_OK != deflateEnd(&z)) {
19790                 return -1;
19791         }
19792 -       
19793 +
19794         return 0;
19795  }
19796  
19797  static int deflate_file_to_buffer_deflate(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
19798         z_stream z;
19799 -       
19800 +
19801         UNUSED(srv);
19802         UNUSED(con);
19803  
19804         z.zalloc = Z_NULL;
19805         z.zfree = Z_NULL;
19806         z.opaque = Z_NULL;
19807 -       
19808 -       if (Z_OK != deflateInit2(&z, 
19809 +
19810 +       if (Z_OK != deflateInit2(&z,
19811                                  Z_DEFAULT_COMPRESSION,
19812 -                                Z_DEFLATED, 
19813 +                                Z_DEFLATED,
19814                                  -MAX_WBITS,  /* supress zlib-header */
19815                                  8,
19816                                  Z_DEFAULT_STRATEGY)) {
19817                 return -1;
19818         }
19819 -               
19820 +
19821         z.next_in = start;
19822         z.avail_in = st_size;
19823         z.total_in = 0;
19824 -               
19825 +
19826         buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12);
19827 -       
19828 +
19829         z.next_out = (unsigned char *)p->b->ptr;
19830         z.avail_out = p->b->size;
19831         z.total_out = 0;
19832 -       
19833 +
19834         if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
19835                 deflateEnd(&z);
19836                 return -1;
19837         }
19838 -       
19839 +
19840         /* trailer */
19841         p->b->used += z.total_out;
19842 -       
19843 +
19844         if (Z_OK != deflateEnd(&z)) {
19845                 return -1;
19846         }
19847 -       
19848 +
19849         return 0;
19850  }
19851  
19852 @@ -274,48 +305,48 @@
19853  #ifdef USE_BZ2LIB
19854  static int deflate_file_to_buffer_bzip2(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
19855         bz_stream bz;
19856 -       
19857 +
19858         UNUSED(srv);
19859         UNUSED(con);
19860  
19861         bz.bzalloc = NULL;
19862         bz.bzfree = NULL;
19863         bz.opaque = NULL;
19864 -       
19865 -       if (BZ_OK != BZ2_bzCompressInit(&bz, 
19866 +
19867 +       if (BZ_OK != BZ2_bzCompressInit(&bz,
19868                                         9, /* blocksize = 900k */
19869                                         0, /* no output */
19870                                         0)) { /* workFactor: default */
19871                 return -1;
19872         }
19873 -               
19874 +
19875         bz.next_in = (char *)start;
19876         bz.avail_in = st_size;
19877         bz.total_in_lo32 = 0;
19878         bz.total_in_hi32 = 0;
19879 -               
19880 +
19881         buffer_prepare_copy(p->b, (bz.avail_in * 1.1) + 12);
19882 -       
19883 +
19884         bz.next_out = p->b->ptr;
19885         bz.avail_out = p->b->size;
19886         bz.total_out_lo32 = 0;
19887         bz.total_out_hi32 = 0;
19888 -       
19889 +
19890         if (BZ_STREAM_END != BZ2_bzCompress(&bz, BZ_FINISH)) {
19891                 BZ2_bzCompressEnd(&bz);
19892                 return -1;
19893         }
19894 -       
19895 +
19896         /* file is too large for now */
19897         if (bz.total_out_hi32) return -1;
19898 -       
19899 +
19900         /* trailer */
19901         p->b->used = bz.total_out_lo32;
19902 -       
19903 +
19904         if (BZ_OK != BZ2_bzCompressEnd(&bz)) {
19905                 return -1;
19906         }
19907 -       
19908 +
19909         return 0;
19910  }
19911  #endif
19912 @@ -326,47 +357,50 @@
19913         void *start;
19914         const char *filename = fn->ptr;
19915         ssize_t r;
19916 -       
19917 +       stat_cache_entry *compressed_sce = NULL;
19918 +
19919 +       if (buffer_is_empty(p->conf.compress_cache_dir)) return -1;
19920 +
19921         /* overflow */
19922         if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
19923 -       
19924 -       /* don't mmap files > 128Mb 
19925 -        * 
19926 +
19927 +       /* don't mmap files > 128Mb
19928 +        *
19929          * we could use a sliding window, but currently there is no need for it
19930          */
19931 -       
19932 +
19933         if (sce->st.st_size > 128 * 1024 * 1024) return -1;
19934 -       
19935 +
19936         buffer_reset(p->ofn);
19937         buffer_copy_string_buffer(p->ofn, p->conf.compress_cache_dir);
19938 -       BUFFER_APPEND_SLASH(p->ofn);
19939 -       
19940 +       PATHNAME_APPEND_SLASH(p->ofn);
19941 +
19942         if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) {
19943                 size_t offset = p->ofn->used - 1;
19944                 char *dir, *nextdir;
19945 -               
19946 +
19947                 buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1);
19948 -               
19949 +
19950                 buffer_copy_string_buffer(p->b, p->ofn);
19951 -               
19952 +
19953                 /* mkdir -p ... */
19954                 for (dir = p->b->ptr + offset; NULL != (nextdir = strchr(dir, '/')); dir = nextdir + 1) {
19955                         *nextdir = '\0';
19956 -                       
19957 +
19958                         if (-1 == mkdir(p->b->ptr, 0700)) {
19959                                 if (errno != EEXIST) {
19960                                         log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cache-directory", p->b, "failed", strerror(errno));
19961 -                                       
19962 +
19963                                         return -1;
19964                                 }
19965                         }
19966 -                       
19967 +
19968                         *nextdir = '/';
19969                 }
19970         } else {
19971                 buffer_append_string_buffer(p->ofn, con->uri.path);
19972         }
19973 -       
19974 +
19975         switch(type) {
19976         case HTTP_ACCEPT_ENCODING_GZIP:
19977                 buffer_append_string(p->ofn, "-gzip-");
19978 @@ -381,55 +415,64 @@
19979                 log_error_write(srv, __FILE__, __LINE__, "sd", "unknown compression type", type);
19980                 return -1;
19981         }
19982 -       
19983 +
19984         buffer_append_string_buffer(p->ofn, sce->etag);
19985 -       
19986 +
19987 +
19988 +       if (HANDLER_ERROR != stat_cache_get_entry(srv, con, p->ofn, &compressed_sce)) {
19989 +               /* file exists */
19990 +
19991 +               http_chunk_append_file(srv, con, p->ofn, 0, compressed_sce->st.st_size);
19992 +               con->file_finished = 1;
19993 +
19994 +               return 0;
19995 +       }
19996 +
19997         if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600))) {
19998                 if (errno == EEXIST) {
19999                         /* cache-entry exists */
20000 -#if 0
20001 -                       log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache hit");
20002 -#endif
20003 -                       buffer_copy_string_buffer(con->physical.path, p->ofn);
20004 -                       
20005 -                       return 0;
20006 +
20007                 }
20008 -               
20009 -               log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cachefile", p->ofn, "failed", strerror(errno));
20010 -               
20011 +
20012 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
20013 +                               "creating cachefile", p->ofn,
20014 +                               "failed", strerror(errno));
20015 +
20016                 return -1;
20017         }
20018 -#if 0
20019 -       log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache miss");
20020 -#endif 
20021 +
20022         if (-1 == (ifd = open(filename, O_RDONLY | O_BINARY))) {
20023 -               log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
20024 -               
20025 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
20026 +                               "opening plain-file", fn,
20027 +                               "failed", strerror(errno));
20028 +
20029                 close(ofd);
20030 -               
20031 +
20032                 return -1;
20033         }
20034 -       
20035 -       
20036 +
20037 +
20038         if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
20039 -               log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
20040 -               
20041 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
20042 +                               "mmaping", fn,
20043 +                               "failed", strerror(errno));
20044 +
20045                 close(ofd);
20046                 close(ifd);
20047                 return -1;
20048         }
20049 -       
20050 +
20051         switch(type) {
20052  #ifdef USE_ZLIB
20053 -       case HTTP_ACCEPT_ENCODING_GZIP: 
20054 +       case HTTP_ACCEPT_ENCODING_GZIP:
20055                 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
20056                 break;
20057 -       case HTTP_ACCEPT_ENCODING_DEFLATE: 
20058 +       case HTTP_ACCEPT_ENCODING_DEFLATE:
20059                 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
20060                 break;
20061  #endif
20062  #ifdef USE_BZ2LIB
20063 -       case HTTP_ACCEPT_ENCODING_BZIP2: 
20064 +       case HTTP_ACCEPT_ENCODING_BZIP2:
20065                 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
20066                 break;
20067  #endif
20068 @@ -437,26 +480,27 @@
20069                 ret = -1;
20070                 break;
20071         }
20072 -       
20073 +
20074         if (-1 == (r = write(ofd, p->b->ptr, p->b->used))) {
20075 -               munmap(start, sce->st.st_size); 
20076 +               munmap(start, sce->st.st_size);
20077                 close(ofd);
20078                 close(ifd);
20079                 return -1;
20080         }
20081 -       
20082 +
20083         if ((size_t)r != p->b->used) {
20084 -               
20085 +
20086         }
20087 -               
20088 +
20089         munmap(start, sce->st.st_size);
20090         close(ofd);
20091         close(ifd);
20092 -       
20093 +
20094         if (ret != 0) return -1;
20095 -       
20096 -       buffer_copy_string_buffer(con->physical.path, p->ofn);
20097 -       
20098 +
20099 +       http_chunk_append_file(srv, con, p->ofn, 0, r);
20100 +       con->file_finished = 1;
20101 +
20102         return 0;
20103  }
20104  
20105 @@ -465,43 +509,44 @@
20106         int ret = -1;
20107         void *start;
20108         buffer *b;
20109 -       
20110 +
20111         /* overflow */
20112         if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
20113 -       
20114 +
20115         /* don't mmap files > 128M
20116 -        * 
20117 +        *
20118          * we could use a sliding window, but currently there is no need for it
20119          */
20120 -       
20121 +
20122         if (sce->st.st_size > 128 * 1024 * 1024) return -1;
20123 -       
20124 -       
20125 +
20126         if (-1 == (ifd = open(fn->ptr, O_RDONLY | O_BINARY))) {
20127                 log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
20128 -               
20129 +
20130                 return -1;
20131         }
20132 -       
20133 -       
20134 -       if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
20135 +
20136 +       start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0);
20137 +
20138 +       close(ifd);
20139 +
20140 +       if (MAP_FAILED == start) {
20141                 log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
20142 -               
20143 -               close(ifd);
20144 +
20145                 return -1;
20146         }
20147 -       
20148 +
20149         switch(type) {
20150  #ifdef USE_ZLIB
20151 -       case HTTP_ACCEPT_ENCODING_GZIP: 
20152 +       case HTTP_ACCEPT_ENCODING_GZIP:
20153                 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
20154                 break;
20155 -       case HTTP_ACCEPT_ENCODING_DEFLATE: 
20156 +       case HTTP_ACCEPT_ENCODING_DEFLATE:
20157                 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
20158                 break;
20159  #endif
20160  #ifdef USE_BZ2LIB
20161 -       case HTTP_ACCEPT_ENCODING_BZIP2: 
20162 +       case HTTP_ACCEPT_ENCODING_BZIP2:
20163                 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
20164                 break;
20165  #endif
20166 @@ -509,69 +554,64 @@
20167                 ret = -1;
20168                 break;
20169         }
20170 -               
20171 +
20172         munmap(start, sce->st.st_size);
20173 -       close(ifd);
20174 -       
20175 +
20176         if (ret != 0) return -1;
20177 -       
20178 +
20179         chunkqueue_reset(con->write_queue);
20180         b = chunkqueue_get_append_buffer(con->write_queue);
20181         buffer_copy_memory(b, p->b->ptr, p->b->used + 1);
20182 -       
20183 +
20184         buffer_reset(con->physical.path);
20185 -       
20186 +
20187         con->file_finished = 1;
20188         con->file_started  = 1;
20189 -       
20190 +
20191         return 0;
20192  }
20193  
20194 -
20195 -#define PATCH(x) \
20196 -       p->conf.x = s->x;
20197  static int mod_compress_patch_connection(server *srv, connection *con, plugin_data *p) {
20198         size_t i, j;
20199         plugin_config *s = p->config_storage[0];
20200  
20201 -       PATCH(compress_cache_dir);
20202 -       PATCH(compress);
20203 -       PATCH(compress_max_filesize);
20204 -       
20205 +       PATCH_OPTION(compress_cache_dir);
20206 +       PATCH_OPTION(compress);
20207 +       PATCH_OPTION(compress_max_filesize);
20208 +
20209         /* skip the first, the global context */
20210         for (i = 1; i < srv->config_context->used; i++) {
20211                 data_config *dc = (data_config *)srv->config_context->data[i];
20212                 s = p->config_storage[i];
20213 -               
20214 +
20215                 /* condition didn't match */
20216                 if (!config_check_cond(srv, con, dc)) continue;
20217 -               
20218 +
20219                 /* merge config */
20220                 for (j = 0; j < dc->value->used; j++) {
20221                         data_unset *du = dc->value->data[j];
20222 -                       
20223 +
20224                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.cache-dir"))) {
20225 -                               PATCH(compress_cache_dir);
20226 +                               PATCH_OPTION(compress_cache_dir);
20227                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.filetype"))) {
20228 -                               PATCH(compress);
20229 +                               PATCH_OPTION(compress);
20230                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.max-filesize"))) {
20231 -                               PATCH(compress_max_filesize);
20232 +                               PATCH_OPTION(compress_max_filesize);
20233                         }
20234                 }
20235         }
20236 -       
20237 +
20238         return 0;
20239  }
20240 -#undef PATCH
20241  
20242  PHYSICALPATH_FUNC(mod_compress_physical) {
20243         plugin_data *p = p_d;
20244         size_t m;
20245         off_t max_fsize;
20246         stat_cache_entry *sce = NULL;
20247 -       
20248 +
20249         /* only GET and POST can get compressed */
20250 -       if (con->request.http_method != HTTP_METHOD_GET && 
20251 +       if (con->request.http_method != HTTP_METHOD_GET &&
20252             con->request.http_method != HTTP_METHOD_POST) {
20253                 return HANDLER_GO_ON;
20254         }
20255 @@ -579,46 +619,49 @@
20256         if (buffer_is_empty(con->physical.path)) {
20257                 return HANDLER_GO_ON;
20258         }
20259 -       
20260 +
20261         mod_compress_patch_connection(srv, con, p);
20262 -       
20263 +
20264         max_fsize = p->conf.compress_max_filesize;
20265  
20266         stat_cache_get_entry(srv, con, con->physical.path, &sce);
20267  
20268         /* don't compress files that are too large as we need to much time to handle them */
20269         if (max_fsize && (sce->st.st_size >> 10) > max_fsize) return HANDLER_GO_ON;
20270 -               
20271 +
20272 +       /* compressing the file might lead to larger files instead */
20273 +       if (sce->st.st_size < 128) return HANDLER_GO_ON;
20274 +
20275         /* check if mimetype is in compress-config */
20276         for (m = 0; m < p->conf.compress->used; m++) {
20277                 data_string *compress_ds = (data_string *)p->conf.compress->data[m];
20278 -                       
20279 +
20280                 if (!compress_ds) {
20281                         log_error_write(srv, __FILE__, __LINE__, "sbb", "evil", con->physical.path, con->uri.path);
20282 -                       
20283 +
20284                         return HANDLER_GO_ON;
20285                 }
20286 -               
20287 +
20288                 if (buffer_is_equal(compress_ds->value, sce->content_type)) {
20289                         /* mimetype found */
20290                         data_string *ds;
20291 -                               
20292 +
20293                         /* the response might change according to Accept-Encoding */
20294                         response_header_insert(srv, con, CONST_STR_LEN("Vary"), CONST_STR_LEN("Accept-Encoding"));
20295 -                               
20296 +
20297                         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Encoding"))) {
20298                                 int accept_encoding = 0;
20299                                 char *value = ds->value->ptr;
20300                                 int srv_encodings = 0;
20301                                 int matched_encodings = 0;
20302 -                               
20303 +
20304                                 /* get client side support encodings */
20305                                 if (NULL != strstr(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
20306                                 if (NULL != strstr(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
20307                                 if (NULL != strstr(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS;
20308                                 if (NULL != strstr(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
20309                                 if (NULL != strstr(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY;
20310 -                               
20311 +
20312                                 /* get server side supported ones */
20313  #ifdef USE_BZ2LIB
20314                                 srv_encodings |= HTTP_ACCEPT_ENCODING_BZIP2;
20315 @@ -627,18 +670,31 @@
20316                                 srv_encodings |= HTTP_ACCEPT_ENCODING_GZIP;
20317                                 srv_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
20318  #endif
20319 -                               
20320 +
20321                                 /* find matching entries */
20322                                 matched_encodings = accept_encoding & srv_encodings;
20323 -                               
20324 +
20325                                 if (matched_encodings) {
20326                                         const char *dflt_gzip = "gzip";
20327                                         const char *dflt_deflate = "deflate";
20328                                         const char *dflt_bzip2 = "bzip2";
20329 -                                       
20330 +
20331                                         const char *compression_name = NULL;
20332                                         int compression_type = 0;
20333 -                                       
20334 +                                       buffer *mtime;
20335 +
20336 +                                       mtime = strftime_cache_get(srv, sce->st.st_mtime);
20337 +                                       etag_mutate(con->physical.etag, sce->etag);
20338 +
20339 +                                       response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20340 +                                       response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20341 +
20342 +                                       /* perhaps we don't even have to compress the file as the browser still has the
20343 +                                        * current version */
20344 +                                       if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
20345 +                                               return HANDLER_FINISHED;
20346 +                                       }
20347 +
20348                                         /* select best matching encoding */
20349                                         if (matched_encodings & HTTP_ACCEPT_ENCODING_BZIP2) {
20350                                                 compression_type = HTTP_ACCEPT_ENCODING_BZIP2;
20351 @@ -650,31 +706,21 @@
20352                                                 compression_type = HTTP_ACCEPT_ENCODING_DEFLATE;
20353                                                 compression_name = dflt_deflate;
20354                                         }
20355 -                                       
20356 -                                       /* deflate it */
20357 -                                       if (p->conf.compress_cache_dir->used) {
20358 -                                               if (0 == deflate_file_to_file(srv, con, p,
20359 -                                                                             con->physical.path, sce, compression_type)) {
20360 -                                                       buffer *mtime;
20361 -                                                       
20362 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
20363 -                                                       
20364 -                                                       mtime = strftime_cache_get(srv, sce->st.st_mtime);
20365 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20366 -
20367 -                                                       etag_mutate(con->physical.etag, sce->etag);
20368 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20369 -
20370 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
20371 -
20372 -                                                       return HANDLER_GO_ON;
20373 -                                               }
20374 -                                       } else if (0 == deflate_file_to_buffer(srv, con, p,
20375 -                                                                              con->physical.path, sce, compression_type)) {
20376 -                                                       
20377 -                                               response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
20378 -                                               response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
20379 -                                               
20380 +
20381 +                                       /* deflate it to file (cached) or to memory */
20382 +                                       if (0 == deflate_file_to_file(srv, con, p,
20383 +                                                       con->physical.path, sce, compression_type) ||
20384 +                                           0 == deflate_file_to_buffer(srv, con, p,
20385 +                                                       con->physical.path, sce, compression_type)) {
20386 +
20387 +                                               response_header_overwrite(srv, con,
20388 +                                                               CONST_STR_LEN("Content-Encoding"),
20389 +                                                               compression_name, strlen(compression_name));
20390 +
20391 +                                               response_header_overwrite(srv, con,
20392 +                                                               CONST_STR_LEN("Content-Type"),
20393 +                                                               CONST_BUF_LEN(sce->content_type));
20394 +
20395                                                 return HANDLER_FINISHED;
20396                                         }
20397                                         break;
20398 @@ -682,20 +728,20 @@
20399                         }
20400                 }
20401         }
20402 -       
20403 +
20404         return HANDLER_GO_ON;
20405  }
20406  
20407  int mod_compress_plugin_init(plugin *p) {
20408         p->version     = LIGHTTPD_VERSION_ID;
20409         p->name        = buffer_init_string("compress");
20410 -       
20411 +
20412         p->init        = mod_compress_init;
20413         p->set_defaults = mod_compress_setdefaults;
20414         p->handle_subrequest_start  = mod_compress_physical;
20415         p->cleanup     = mod_compress_free;
20416 -       
20417 +
20418         p->data        = NULL;
20419 -       
20420 +
20421         return 0;
20422  }
20423 --- ../lighttpd-1.4.11/src/mod_dirlisting.c     2006-01-13 00:00:45.000000000 +0200
20424 +++ lighttpd-1.4.12/src/mod_dirlisting.c        2006-07-16 00:26:04.000000000 +0300
20425 @@ -1,11 +1,9 @@
20426  #include <ctype.h>
20427  #include <stdlib.h>
20428  #include <string.h>
20429 -#include <dirent.h>
20430  #include <assert.h>
20431  #include <errno.h>
20432  #include <stdio.h>
20433 -#include <unistd.h>
20434  #include <time.h>
20435  
20436  #include "base.h"
20437 @@ -17,6 +15,9 @@
20438  #include "response.h"
20439  #include "stat_cache.h"
20440  #include "stream.h"
20441 +#include "etag.h"
20442 +
20443 +#include "sys-strings.h"
20444  
20445  /**
20446   * this is a dirlisting for a lighttpd plugin
20447 @@ -27,10 +28,13 @@
20448  #include <sys/syslimits.h>
20449  #endif
20450  
20451 -#ifdef HAVE_ATTR_ATTRIBUTES_H
20452 +#ifdef HAVE_XATTR
20453  #include <attr/attributes.h>
20454  #endif
20455  
20456 +#include "sys-files.h"
20457 +#include "sys-strings.h"
20458 +
20459  /* plugin config for all request/connections */
20460  
20461  typedef struct {
20462 @@ -54,7 +58,7 @@
20463         unsigned short hide_readme_file;
20464         unsigned short show_header;
20465         unsigned short hide_header_file;
20466 -       
20467 +
20468         excludes_buffer *excludes;
20469  
20470         buffer *external_css;
20471 @@ -63,13 +67,14 @@
20472  
20473  typedef struct {
20474         PLUGIN_DATA;
20475 -       
20476 +
20477         buffer *tmp_buf;
20478         buffer *content_charset;
20479 -       
20480 +       buffer *path;
20481 +
20482         plugin_config **config_storage;
20483 -       
20484 -       plugin_config conf; 
20485 +
20486 +       plugin_config conf;
20487  } plugin_data;
20488  
20489  excludes_buffer *excludes_buffer_init(void) {
20490 @@ -146,44 +151,46 @@
20491  /* init the plugin data */
20492  INIT_FUNC(mod_dirlisting_init) {
20493         plugin_data *p;
20494 -       
20495 +
20496         p = calloc(1, sizeof(*p));
20497  
20498         p->tmp_buf = buffer_init();
20499         p->content_charset = buffer_init();
20500 -       
20501 +       p->path = buffer_init();
20502 +
20503         return p;
20504  }
20505  
20506  /* detroy the plugin data */
20507  FREE_FUNC(mod_dirlisting_free) {
20508         plugin_data *p = p_d;
20509 -       
20510 +
20511         UNUSED(srv);
20512  
20513         if (!p) return HANDLER_GO_ON;
20514 -       
20515 +
20516         if (p->config_storage) {
20517                 size_t i;
20518                 for (i = 0; i < srv->config_context->used; i++) {
20519                         plugin_config *s = p->config_storage[i];
20520 -                       
20521 +
20522                         if (!s) continue;
20523 -                       
20524 +
20525                         excludes_buffer_free(s->excludes);
20526                         buffer_free(s->external_css);
20527                         buffer_free(s->encoding);
20528 -                       
20529 +
20530                         free(s);
20531                 }
20532                 free(p->config_storage);
20533         }
20534 -       
20535 +
20536         buffer_free(p->tmp_buf);
20537 +       buffer_free(p->path);
20538         buffer_free(p->content_charset);
20539 -       
20540 +
20541         free(p);
20542 -       
20543 +
20544         return HANDLER_GO_ON;
20545  }
20546  
20547 @@ -215,10 +222,10 @@
20548                         if (0 != excludes_buffer_append(s->excludes,
20549                                     ((data_string *)(da->value->data[j]))->value)) {
20550  #ifdef HAVE_PCRE_H
20551 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
20552 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
20553                                                 "pcre-compile failed for", ((data_string *)(da->value->data[j]))->value);
20554  #else
20555 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
20556 +                               log_error_write(srv, __FILE__, __LINE__, "s",
20557                                                 "pcre support is missing, please install libpcre and the headers");
20558  #endif
20559                         }
20560 @@ -233,8 +240,8 @@
20561  SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
20562         plugin_data *p = p_d;
20563         size_t i = 0;
20564 -       
20565 -       config_values_t cv[] = { 
20566 +
20567 +       config_values_t cv[] = {
20568                 { "dir-listing.exclude",          NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },   /* 0 */
20569                 { "dir-listing.activate",         NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
20570                 { "dir-listing.hide-dotfiles",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
20571 @@ -245,18 +252,18 @@
20572                 { "dir-listing.show-header",      NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
20573                 { "dir-listing.hide-header-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
20574                 { "server.dir-listing",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
20575 -               
20576 +
20577                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
20578         };
20579 -       
20580 +
20581         if (!p) return HANDLER_ERROR;
20582 -       
20583 +
20584         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
20585 -       
20586 +
20587         for (i = 0; i < srv->config_context->used; i++) {
20588                 plugin_config *s;
20589                 array *ca;
20590 -               
20591 +
20592                 s = calloc(1, sizeof(plugin_config));
20593                 s->excludes = excludes_buffer_init();
20594                 s->dir_listing = 0;
20595 @@ -267,7 +274,7 @@
20596                 s->show_header = 0;
20597                 s->hide_header_file = 0;
20598                 s->encoding = buffer_init();
20599 -               
20600 +
20601                 cv[0].destination = s->excludes;
20602                 cv[1].destination = &(s->dir_listing);
20603                 cv[2].destination = &(s->hide_dot_files);
20604 @@ -292,60 +299,57 @@
20605         return HANDLER_GO_ON;
20606  }
20607  
20608 -#define PATCH(x) \
20609 -       p->conf.x = s->x;
20610  static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_data *p) {
20611         size_t i, j;
20612         plugin_config *s = p->config_storage[0];
20613  
20614 -       PATCH(dir_listing);
20615 -       PATCH(external_css);
20616 -       PATCH(hide_dot_files);
20617 -       PATCH(encoding);
20618 -       PATCH(show_readme);
20619 -       PATCH(hide_readme_file);
20620 -       PATCH(show_header);
20621 -       PATCH(hide_header_file);
20622 -       PATCH(excludes);
20623 -       
20624 +       PATCH_OPTION(dir_listing);
20625 +       PATCH_OPTION(external_css);
20626 +       PATCH_OPTION(hide_dot_files);
20627 +       PATCH_OPTION(encoding);
20628 +       PATCH_OPTION(show_readme);
20629 +       PATCH_OPTION(hide_readme_file);
20630 +       PATCH_OPTION(show_header);
20631 +       PATCH_OPTION(hide_header_file);
20632 +       PATCH_OPTION(excludes);
20633 +
20634         /* skip the first, the global context */
20635         for (i = 1; i < srv->config_context->used; i++) {
20636                 data_config *dc = (data_config *)srv->config_context->data[i];
20637                 s = p->config_storage[i];
20638 -               
20639 +
20640                 /* condition didn't match */
20641                 if (!config_check_cond(srv, con, dc)) continue;
20642 -               
20643 +
20644                 /* merge config */
20645                 for (j = 0; j < dc->value->used; j++) {
20646                         data_unset *du = dc->value->data[j];
20647 -                       
20648 +
20649                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.activate")) ||
20650                             buffer_is_equal_string(du->key, CONST_STR_LEN("server.dir-listing"))) {
20651 -                               PATCH(dir_listing);
20652 +                               PATCH_OPTION(dir_listing);
20653                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-dotfiles"))) {
20654 -                               PATCH(hide_dot_files);
20655 +                               PATCH_OPTION(hide_dot_files);
20656                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.external-css"))) {
20657 -                               PATCH(external_css);
20658 +                               PATCH_OPTION(external_css);
20659                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.encoding"))) {
20660 -                               PATCH(encoding);
20661 +                               PATCH_OPTION(encoding);
20662                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-readme"))) {
20663 -                               PATCH(show_readme);
20664 +                               PATCH_OPTION(show_readme);
20665                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-readme-file"))) {
20666 -                               PATCH(hide_readme_file);
20667 +                               PATCH_OPTION(hide_readme_file);
20668                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-header"))) {
20669 -                               PATCH(show_header);
20670 +                               PATCH_OPTION(show_header);
20671                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-header-file"))) {
20672 -                               PATCH(hide_header_file);
20673 +                               PATCH_OPTION(hide_header_file);
20674                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.excludes"))) {
20675 -                               PATCH(excludes);
20676 +                               PATCH_OPTION(excludes);
20677                         }
20678                 }
20679         }
20680 -       
20681 +
20682         return 0;
20683  }
20684 -#undef PATCH
20685  
20686  typedef struct {
20687         size_t  namelen;
20688 @@ -432,7 +436,7 @@
20689  
20690  static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) {
20691         UNUSED(srv);
20692 -       
20693 +
20694         BUFFER_APPEND_STRING_CONST(out,
20695                 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
20696                 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n"
20697 @@ -492,11 +496,11 @@
20698         if (p->conf.show_header) {
20699                 stream s;
20700                 /* if we have a HEADER file, display it in <pre class="header"></pre> */
20701 -               
20702 +
20703                 buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
20704 -               BUFFER_APPEND_SLASH(p->tmp_buf);
20705 +               PATHNAME_APPEND_SLASH(p->tmp_buf);
20706                 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "HEADER.txt");
20707 -               
20708 +
20709                 if (-1 != stream_open(&s, p->tmp_buf)) {
20710                         BUFFER_APPEND_STRING_CONST(out, "<pre class=\"header\">");
20711                         buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
20712 @@ -531,21 +535,21 @@
20713  
20714  static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) {
20715         UNUSED(srv);
20716 -       
20717 +
20718         BUFFER_APPEND_STRING_CONST(out,
20719                 "</tbody>\n"
20720                 "</table>\n"
20721                 "</div>\n"
20722         );
20723 -       
20724 +
20725         if (p->conf.show_readme) {
20726                 stream s;
20727                 /* if we have a README file, display it in <pre class="readme"></pre> */
20728 -               
20729 +
20730                 buffer_copy_string_buffer(p->tmp_buf,  con->physical.path);
20731 -               BUFFER_APPEND_SLASH(p->tmp_buf);
20732 +               PATHNAME_APPEND_SLASH(p->tmp_buf);
20733                 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "README.txt");
20734 -               
20735 +
20736                 if (-1 != stream_open(&s, p->tmp_buf)) {
20737                         BUFFER_APPEND_STRING_CONST(out, "<pre class=\"readme\">");
20738                         buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
20739 @@ -553,7 +557,7 @@
20740                 }
20741                 stream_close(&s);
20742         }
20743 -       
20744 +
20745         BUFFER_APPEND_STRING_CONST(out,
20746                 "<div class=\"foot\">"
20747         );
20748 @@ -576,7 +580,6 @@
20749         buffer *out;
20750         struct dirent *dent;
20751         struct stat st;
20752 -       char *path, *path_file;
20753         size_t i;
20754         int hide_dotfiles = p->conf.hide_dot_files;
20755         dirls_list_t dirs, files, *list;
20756 @@ -586,6 +589,7 @@
20757         size_t k;
20758         const char *content_type;
20759         long name_max;
20760 +
20761  #ifdef HAVE_XATTR
20762         char attrval[128];
20763         int attrlen;
20764 @@ -594,10 +598,10 @@
20765         struct tm tm;
20766  #endif
20767  
20768 -       if (dir->used == 0) return -1;
20769 -       
20770 -       i = dir->used - 1;
20771 +       /* empty pathname, never ... */
20772 +       if (buffer_is_empty(dir)) return -1;
20773  
20774 +       /* max-length for the opendir */
20775  #ifdef HAVE_PATHCONF
20776         if (-1 == (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) {
20777  #ifdef NAME_MAX
20778 @@ -606,22 +610,24 @@
20779                 name_max = 256; /* stupid default */
20780  #endif
20781         }
20782 -#elif defined __WIN32
20783 +#elif defined _WIN32
20784         name_max = FILENAME_MAX;
20785  #else
20786         name_max = NAME_MAX;
20787  #endif
20788 -       
20789 -       path = malloc(dir->used + name_max);
20790 -       assert(path);
20791 -       strcpy(path, dir->ptr);
20792 -       path_file = path + i;
20793  
20794 -       if (NULL == (dp = opendir(path))) {
20795 -               log_error_write(srv, __FILE__, __LINE__, "sbs", 
20796 +       buffer_copy_string_buffer(p->path, dir);
20797 +       PATHNAME_APPEND_SLASH(p->path);
20798 +
20799 +#ifdef _WIN32
20800 +       /* append *.* to the path */
20801 +       buffer_append_string(path, "*.*");
20802 +#endif
20803 +
20804 +       if (NULL == (dp = opendir(p->path->ptr))) {
20805 +               log_error_write(srv, __FILE__, __LINE__, "sbs",
20806                         "opendir failed:", dir, strerror(errno));
20807  
20808 -               free(path);
20809                 return -1;
20810         }
20811  
20812 @@ -633,7 +639,7 @@
20813         assert(files.ent);
20814         files.size = DIRLIST_BLOB_SIZE;
20815         files.used = 0;
20816 -       
20817 +
20818         while ((dent = readdir(dp)) != NULL) {
20819                 unsigned short exclude_match = 0;
20820  
20821 @@ -686,15 +692,21 @@
20822  #endif
20823  
20824                 i = strlen(dent->d_name);
20825 -               
20826 +
20827                 /* NOTE: the manual says, d_name is never more than NAME_MAX
20828                  *       so this should actually not be a buffer-overflow-risk
20829                  */
20830                 if (i > (size_t)name_max) continue;
20831 -               
20832 -               memcpy(path_file, dent->d_name, i + 1);
20833 -               if (stat(path, &st) != 0)
20834 +
20835 +               /* build the dirname */
20836 +               buffer_copy_string_buffer(p->path, dir);
20837 +               PATHNAME_APPEND_SLASH(p->path);
20838 +               buffer_append_string(p->path, dent->d_name);
20839 +
20840 +               if (stat(p->path->ptr, &st) != 0) {
20841 +                       fprintf(stderr, "%s.%d: %s, %s\r\n", __FILE__, __LINE__, p->path->ptr, strerror(errno));
20842                         continue;
20843 +               }
20844  
20845                 list = &files;
20846                 if (S_ISDIR(st.st_mode))
20847 @@ -740,7 +752,7 @@
20848  #else
20849                 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
20850  #endif
20851 -               
20852 +
20853                 BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
20854                 buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
20855                 BUFFER_APPEND_STRING_CONST(out, "/\">");
20856 @@ -757,18 +769,22 @@
20857                 tmp = files.ent[i];
20858  
20859                 content_type = NULL;
20860 +
20861  #ifdef HAVE_XATTR
20862 -               
20863                 if (con->conf.use_xattr) {
20864 -                       memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
20865 +                       /* build the dirname */
20866 +                       buffer_copy_string_buffer(p->path, dir);
20867 +                       PATHNAME_APPEND_SLASH(p->path);
20868 +                       buffer_append_string_len(p->path, DIRLIST_ENT_NAME(tmp), tmp->namelen);
20869 +
20870                         attrlen = sizeof(attrval) - 1;
20871 -                       if (attr_get(path, "Content-Type", attrval, &attrlen, 0) == 0) {
20872 +                       if (attr_get(p->path->ptr, "Content-Type", attrval, &attrlen, 0) == 0) {
20873                                 attrval[attrlen] = '\0';
20874                                 content_type = attrval;
20875                         }
20876                 }
20877  #endif
20878 -               
20879 +
20880                 if (content_type == NULL) {
20881                         content_type = "application/octet-stream";
20882                         for (k = 0; k < con->conf.mimetypes->used; k++) {
20883 @@ -788,7 +804,7 @@
20884                                 }
20885                         }
20886                 }
20887 -                       
20888 +
20889  #ifdef HAVE_LOCALTIME_R
20890                 localtime_r(&(tmp->mtime), &tm);
20891                 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
20892 @@ -814,7 +830,6 @@
20893  
20894         free(files.ent);
20895         free(dirs.ent);
20896 -       free(path);
20897  
20898         http_list_directory_footer(srv, con, p, out);
20899  
20900 @@ -837,36 +852,55 @@
20901  URIHANDLER_FUNC(mod_dirlisting_subrequest) {
20902         plugin_data *p = p_d;
20903         stat_cache_entry *sce = NULL;
20904 -       
20905 -       UNUSED(srv);
20906 -       
20907 -       if (con->physical.path->used == 0) return HANDLER_GO_ON;
20908 -       if (con->uri.path->used == 0) return HANDLER_GO_ON;
20909 +       buffer *mtime;
20910 +       data_string *ds;
20911 +
20912 +       if (con->uri.path->used < 2) return HANDLER_GO_ON;
20913         if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
20914 -       
20915 +       if (con->physical.path->used == 0) return HANDLER_GO_ON;
20916 +
20917         mod_dirlisting_patch_connection(srv, con, p);
20918  
20919         if (!p->conf.dir_listing) return HANDLER_GO_ON;
20920 -       
20921 +
20922 +       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
20923 +               /* just a second ago the file was still there */
20924 +               return HANDLER_GO_ON;
20925 +       }
20926 +
20927 +       if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
20928 +
20929         if (con->conf.log_request_handling) {
20930                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling the request as Dir-Listing");
20931                 log_error_write(srv, __FILE__, __LINE__,  "sb", "URI          :", con->uri.path);
20932         }
20933 -       
20934 -       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
20935 -               fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, con->physical.path->ptr);
20936 -               SEGFAULT();
20937 +
20938 +       /* perhaps this a cachable request
20939 +        * - we use the etag of the directory
20940 +        * */
20941 +
20942 +       etag_mutate(con->physical.etag, sce->etag);
20943 +       response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20944 +
20945 +       /* prepare header */
20946 +       if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
20947 +               mtime = strftime_cache_get(srv, sce->st.st_mtime);
20948 +               response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20949 +       } else {
20950 +               mtime = ds->value;
20951         }
20952 -       
20953 -       if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
20954 -       
20955 +
20956 +       if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
20957 +               return HANDLER_FINISHED;
20958 +       }
20959 +
20960         if (http_list_directory(srv, con, p, con->physical.path)) {
20961                 /* dirlisting failed */
20962                 con->http_status = 403;
20963         }
20964 -       
20965 +
20966         buffer_reset(con->physical.path);
20967 -       
20968 +
20969         /* not found */
20970         return HANDLER_FINISHED;
20971  }
20972 @@ -876,13 +910,13 @@
20973  int mod_dirlisting_plugin_init(plugin *p) {
20974         p->version     = LIGHTTPD_VERSION_ID;
20975         p->name        = buffer_init_string("dirlisting");
20976 -       
20977 +
20978         p->init        = mod_dirlisting_init;
20979         p->handle_subrequest_start  = mod_dirlisting_subrequest;
20980         p->set_defaults  = mod_dirlisting_set_defaults;
20981         p->cleanup     = mod_dirlisting_free;
20982 -       
20983 +
20984         p->data        = NULL;
20985 -       
20986 +
20987         return 0;
20988  }
20989 --- ../lighttpd-1.4.11/src/mod_evasive.c        2006-01-04 15:24:51.000000000 +0200
20990 +++ lighttpd-1.4.12/src/mod_evasive.c   2006-07-16 00:26:04.000000000 +0300
20991 @@ -31,100 +31,97 @@
20992  
20993  typedef struct {
20994         PLUGIN_DATA;
20995 -       
20996 +
20997         plugin_config **config_storage;
20998 -       
20999 -       plugin_config conf; 
21000 +
21001 +       plugin_config conf;
21002  } plugin_data;
21003  
21004  INIT_FUNC(mod_evasive_init) {
21005         plugin_data *p;
21006 -       
21007 +
21008         p = calloc(1, sizeof(*p));
21009 -       
21010 +
21011         return p;
21012  }
21013  
21014  FREE_FUNC(mod_evasive_free) {
21015         plugin_data *p = p_d;
21016 -       
21017 +
21018         UNUSED(srv);
21019  
21020         if (!p) return HANDLER_GO_ON;
21021 -       
21022 +
21023         if (p->config_storage) {
21024                 size_t i;
21025                 for (i = 0; i < srv->config_context->used; i++) {
21026                         plugin_config *s = p->config_storage[i];
21027 -                                               
21028 +
21029                         free(s);
21030                 }
21031                 free(p->config_storage);
21032         }
21033 -       
21034 +
21035         free(p);
21036 -       
21037 +
21038         return HANDLER_GO_ON;
21039  }
21040  
21041  SETDEFAULTS_FUNC(mod_evasive_set_defaults) {
21042         plugin_data *p = p_d;
21043         size_t i = 0;
21044 -       
21045 -       config_values_t cv[] = { 
21046 +
21047 +       config_values_t cv[] = {
21048                 { "evasive.max-conns-per-ip",    NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
21049                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21050         };
21051 -       
21052 +
21053         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21054 -       
21055 +
21056         for (i = 0; i < srv->config_context->used; i++) {
21057                 plugin_config *s;
21058 -               
21059 +
21060                 s = calloc(1, sizeof(plugin_config));
21061                 s->max_conns       = 0;
21062 -               
21063 +
21064                 cv[0].destination = &(s->max_conns);
21065 -               
21066 +
21067                 p->config_storage[i] = s;
21068 -       
21069 +
21070                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
21071                         return HANDLER_ERROR;
21072                 }
21073         }
21074 -       
21075 +
21076         return HANDLER_GO_ON;
21077  }
21078  
21079 -#define PATCH(x) \
21080 -       p->conf.x = s->x;
21081  static int mod_evasive_patch_connection(server *srv, connection *con, plugin_data *p) {
21082         size_t i, j;
21083         plugin_config *s = p->config_storage[0];
21084  
21085 -       PATCH(max_conns);
21086 -       
21087 +       PATCH_OPTION(max_conns);
21088 +
21089         /* skip the first, the global context */
21090         for (i = 1; i < srv->config_context->used; i++) {
21091                 data_config *dc = (data_config *)srv->config_context->data[i];
21092                 s = p->config_storage[i];
21093 -               
21094 +
21095                 /* condition didn't match */
21096                 if (!config_check_cond(srv, con, dc)) continue;
21097 -               
21098 +
21099                 /* merge config */
21100                 for (j = 0; j < dc->value->used; j++) {
21101                         data_unset *du = dc->value->data[j];
21102 -                       
21103 +
21104                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.max-conns-per-ip"))) {
21105 -                               PATCH(max_conns);
21106 +                               PATCH_OPTION(max_conns);
21107                         }
21108                 }
21109         }
21110 -       
21111 +
21112         return 0;
21113  }
21114 -#undef PATCH
21115  
21116  URIHANDLER_FUNC(mod_evasive_uri_handler) {
21117         plugin_data *p = p_d;
21118 @@ -132,10 +129,10 @@
21119         size_t j;
21120  
21121         if (con->uri.path->used == 0) return HANDLER_GO_ON;
21122 -       
21123 +
21124         mod_evasive_patch_connection(srv, con, p);
21125 -       
21126 -       /* no limit set, nothing to block */    
21127 +
21128 +       /* no limit set, nothing to block */
21129         if (p->conf.max_conns == 0) return HANDLER_GO_ON;
21130  
21131         for (j = 0; j < srv->conns->used; j++) {
21132 @@ -147,7 +144,7 @@
21133                 if (c->dst_addr.ipv4.sin_addr.s_addr == con->dst_addr.ipv4.sin_addr.s_addr &&
21134                     c->state > CON_STATE_REQUEST_END) {
21135                         conns_by_ip++;
21136 -       
21137 +
21138                         if (conns_by_ip > p->conf.max_conns) {
21139                                 log_error_write(srv, __FILE__, __LINE__, "ss",
21140                                         inet_ntop_cache_get_ip(srv, &(con->dst_addr)),
21141 @@ -158,7 +155,7 @@
21142                         }
21143                 }
21144         }
21145 -       
21146 +
21147         return HANDLER_GO_ON;
21148  }
21149  
21150 @@ -166,13 +163,13 @@
21151  int mod_evasive_plugin_init(plugin *p) {
21152         p->version     = LIGHTTPD_VERSION_ID;
21153         p->name        = buffer_init_string("evasive");
21154 -       
21155 +
21156         p->init        = mod_evasive_init;
21157         p->set_defaults = mod_evasive_set_defaults;
21158         p->handle_uri_clean  = mod_evasive_uri_handler;
21159         p->cleanup     = mod_evasive_free;
21160 -       
21161 +
21162         p->data        = NULL;
21163 -       
21164 +
21165         return 0;
21166  }
21167 --- ../lighttpd-1.4.11/src/mod_evhost.c 2005-08-17 10:42:03.000000000 +0300
21168 +++ lighttpd-1.4.12/src/mod_evhost.c    2006-07-16 00:26:03.000000000 +0300
21169 @@ -7,10 +7,12 @@
21170  #include "response.h"
21171  #include "stat_cache.h"
21172  
21173 +#include "sys-files.h"
21174 +
21175  typedef struct {
21176         /* unparsed pieces */
21177         buffer *path_pieces_raw;
21178 -       
21179 +
21180         /* pieces for path creation */
21181         size_t len;
21182         buffer **path_pieces;
21183 @@ -21,14 +23,14 @@
21184         buffer *tmp_buf;
21185  
21186         plugin_config **config_storage;
21187 -       plugin_config conf; 
21188 +       plugin_config conf;
21189  } plugin_data;
21190  
21191  INIT_FUNC(mod_evhost_init) {
21192         plugin_data *p;
21193 -       
21194 +
21195         p = calloc(1, sizeof(*p));
21196 -       
21197 +
21198         p->tmp_buf = buffer_init();
21199  
21200         return p;
21201 @@ -36,34 +38,34 @@
21202  
21203  FREE_FUNC(mod_evhost_free) {
21204         plugin_data *p = p_d;
21205 -       
21206 +
21207         UNUSED(srv);
21208  
21209         if (!p) return HANDLER_GO_ON;
21210 -       
21211 +
21212         if (p->config_storage) {
21213                 size_t i;
21214                 for (i = 0; i < srv->config_context->used; i++) {
21215                         plugin_config *s = p->config_storage[i];
21216  
21217                         if (!s) continue;
21218 -                       
21219 +
21220                         if(s->path_pieces) {
21221                                 size_t j;
21222                                 for (j = 0; j < s->len; j++) {
21223                                         buffer_free(s->path_pieces[j]);
21224                                 }
21225 -                               
21226 +
21227                                 free(s->path_pieces);
21228                         }
21229 -                       
21230 +
21231                         buffer_free(s->path_pieces_raw);
21232 -                       
21233 +
21234                         free(s);
21235                 }
21236                 free(p->config_storage);
21237         }
21238 -       
21239 +
21240         buffer_free(p->tmp_buf);
21241  
21242         free(p);
21243 @@ -73,30 +75,30 @@
21244  
21245  static void mod_evhost_parse_pattern(plugin_config *s) {
21246         char *ptr = s->path_pieces_raw->ptr,*pos;
21247 -       
21248 +
21249         s->path_pieces = NULL;
21250 -       
21251 +
21252         for(pos=ptr;*ptr;ptr++) {
21253                 if(*ptr == '%') {
21254                         s->path_pieces = realloc(s->path_pieces,(s->len+2) * sizeof(*s->path_pieces));
21255                         s->path_pieces[s->len] = buffer_init();
21256                         s->path_pieces[s->len+1] = buffer_init();
21257 -                       
21258 +
21259                         buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
21260                         pos = ptr + 2;
21261 -                       
21262 +
21263                         buffer_copy_string_len(s->path_pieces[s->len+1],ptr++,2);
21264 -                       
21265 +
21266                         s->len += 2;
21267                 }
21268         }
21269 -       
21270 +
21271         if(*pos != '\0') {
21272                 s->path_pieces = realloc(s->path_pieces,(s->len+1) * sizeof(*s->path_pieces));
21273                 s->path_pieces[s->len] = buffer_init();
21274 -               
21275 +
21276                 buffer_append_memory(s->path_pieces[s->len],pos,ptr-pos);
21277 -               
21278 +
21279                 s->len += 1;
21280         }
21281  }
21282 @@ -104,9 +106,9 @@
21283  SETDEFAULTS_FUNC(mod_evhost_set_defaults) {
21284         plugin_data *p = p_d;
21285         size_t i;
21286 -       
21287 +
21288         /**
21289 -        * 
21290 +        *
21291          * #
21292          * # define a pattern for the host url finding
21293          * # %% => % sign
21294 @@ -117,39 +119,39 @@
21295          * # %4 => subdomain 2 name
21296          * #
21297          * evhost.path-pattern = "/home/ckruse/dev/www/%3/htdocs/"
21298 -        * 
21299 +        *
21300          */
21301 -       
21302 -       config_values_t cv[] = { 
21303 +
21304 +       config_values_t cv[] = {
21305                 { "evhost.path-pattern",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
21306                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21307         };
21308 -       
21309 +
21310         if (!p) return HANDLER_ERROR;
21311 -       
21312 +
21313         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21314 -       
21315 +
21316         for (i = 0; i < srv->config_context->used; i++) {
21317                 plugin_config *s;
21318 -               
21319 +
21320                 s = calloc(1, sizeof(plugin_config));
21321                 s->path_pieces_raw = buffer_init();
21322                 s->path_pieces     = NULL;
21323                 s->len             = 0;
21324 -       
21325 +
21326                 cv[0].destination = s->path_pieces_raw;
21327 -               
21328 +
21329                 p->config_storage[i] = s;
21330 -               
21331 +
21332                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value,  cv)) {
21333                         return HANDLER_ERROR;
21334                 }
21335 -               
21336 +
21337                 if (s->path_pieces_raw->used != 0) {
21338                         mod_evhost_parse_pattern(s);
21339                 }
21340         }
21341 -       
21342 +
21343         return HANDLER_GO_ON;
21344  }
21345  
21346 @@ -158,7 +160,7 @@
21347   * - %0 - full hostname (authority w/o port)
21348   * - %1 - tld
21349   * - %2 - domain.tld
21350 - * - %3 - 
21351 + * - %3 -
21352   */
21353  
21354  static int mod_evhost_parse_host(connection *con,array *host) {
21355 @@ -168,7 +170,7 @@
21356         int first = 1;
21357         data_string *ds;
21358         int i;
21359 -       
21360 +
21361         /* first, find the domain + tld */
21362         for(;ptr > con->uri.authority->ptr;ptr--) {
21363                 if(*ptr == '.') {
21364 @@ -179,18 +181,18 @@
21365                         first = 1;
21366                 }
21367         }
21368 -       
21369 +
21370         ds = data_string_init();
21371         buffer_copy_string(ds->key,"%0");
21372 -       
21373 +
21374         /* if we stopped at a dot, skip the dot */
21375         if (*ptr == '.') ptr++;
21376         buffer_copy_string_len(ds->value, ptr, colon-ptr);
21377 -       
21378 +
21379         array_insert_unique(host,(data_unset *)ds);
21380 -       
21381 +
21382         /* if the : is not the start of the authority, go on parsing the hostname */
21383 -       
21384 +
21385         if (colon != con->uri.authority->ptr) {
21386                 for(ptr = colon - 1, i = 1; ptr > con->uri.authority->ptr; ptr--) {
21387                         if(*ptr == '.') {
21388 @@ -200,59 +202,55 @@
21389                                         buffer_copy_string(ds->key,"%");
21390                                         buffer_append_long(ds->key, i++);
21391                                         buffer_copy_string_len(ds->value,ptr+1,colon-ptr-1);
21392 -                                       
21393 +
21394                                         array_insert_unique(host,(data_unset *)ds);
21395                                 }
21396                                 colon = ptr;
21397                         }
21398                 }
21399 -               
21400 +
21401                 /* if the . is not the first charactor of the hostname */
21402                 if (colon != ptr) {
21403                         ds = data_string_init();
21404                         buffer_copy_string(ds->key,"%");
21405                         buffer_append_long(ds->key, i++);
21406                         buffer_copy_string_len(ds->value,ptr,colon-ptr);
21407 -                       
21408 +
21409                         array_insert_unique(host,(data_unset *)ds);
21410                 }
21411         }
21412 -       
21413 +
21414         return 0;
21415  }
21416  
21417 -#define PATCH(x) \
21418 -       p->conf.x = s->x;
21419  static int mod_evhost_patch_connection(server *srv, connection *con, plugin_data *p) {
21420         size_t i, j;
21421         plugin_config *s = p->config_storage[0];
21422 -       
21423 -       PATCH(path_pieces);
21424 -       PATCH(len);
21425 -       
21426 +
21427 +       PATCH_OPTION(path_pieces);
21428 +       PATCH_OPTION(len);
21429 +
21430         /* skip the first, the global context */
21431         for (i = 1; i < srv->config_context->used; i++) {
21432                 data_config *dc = (data_config *)srv->config_context->data[i];
21433                 s = p->config_storage[i];
21434 -               
21435 +
21436                 /* condition didn't match */
21437                 if (!config_check_cond(srv, con, dc)) continue;
21438 -               
21439 +
21440                 /* merge config */
21441                 for (j = 0; j < dc->value->used; j++) {
21442                         data_unset *du = dc->value->data[j];
21443 -                       
21444 +
21445                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("evhost.path-pattern"))) {
21446 -                               PATCH(path_pieces);
21447 -                               PATCH(len);
21448 +                               PATCH_OPTION(path_pieces);
21449 +                               PATCH_OPTION(len);
21450                         }
21451                 }
21452         }
21453 -       
21454 +
21455         return 0;
21456  }
21457 -#undef PATCH
21458 -
21459  
21460  static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d) {
21461         plugin_data *p = p_d;
21462 @@ -261,29 +259,29 @@
21463         register char *ptr;
21464         int not_good = 0;
21465         stat_cache_entry *sce = NULL;
21466 -       
21467 +
21468         /* not authority set */
21469         if (con->uri.authority->used == 0) return HANDLER_GO_ON;
21470 -       
21471 +
21472         mod_evhost_patch_connection(srv, con, p);
21473 -       
21474 +
21475         /* missing even default(global) conf */
21476         if (0 == p->conf.len) {
21477                 return HANDLER_GO_ON;
21478         }
21479  
21480         parsed_host = array_init();
21481 -       
21482 +
21483         mod_evhost_parse_host(con, parsed_host);
21484 -       
21485 +
21486         /* build document-root */
21487         buffer_reset(p->tmp_buf);
21488 -       
21489 +
21490         for (i = 0; i < p->conf.len; i++) {
21491                 ptr = p->conf.path_pieces[i]->ptr;
21492                 if (*ptr == '%') {
21493                         data_string *ds;
21494 -                       
21495 +
21496                         if (*(ptr+1) == '%') {
21497                                 /* %% */
21498                                 BUFFER_APPEND_STRING_CONST(p->tmp_buf,"%");
21499 @@ -298,11 +296,11 @@
21500                         buffer_append_string_buffer(p->tmp_buf,p->conf.path_pieces[i]);
21501                 }
21502         }
21503 -       
21504 -       BUFFER_APPEND_SLASH(p->tmp_buf);
21505 -       
21506 +
21507 +       PATHNAME_APPEND_SLASH(p->tmp_buf);
21508 +
21509         array_free(parsed_host);
21510 -       
21511 +
21512         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
21513                 log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
21514                 not_good = 1;
21515 @@ -310,11 +308,11 @@
21516                 log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", p->tmp_buf);
21517                 not_good = 1;
21518         }
21519 -       
21520 +
21521         if (!not_good) {
21522                 buffer_copy_string_buffer(con->physical.doc_root, p->tmp_buf);
21523         }
21524 -       
21525 +
21526         return HANDLER_GO_ON;
21527  }
21528  
21529 @@ -325,9 +323,9 @@
21530         p->set_defaults            = mod_evhost_set_defaults;
21531         p->handle_docroot          = mod_evhost_uri_handler;
21532         p->cleanup                 = mod_evhost_free;
21533 -       
21534 +
21535         p->data                    = NULL;
21536 -       
21537 +
21538         return 0;
21539  }
21540  
21541 --- ../lighttpd-1.4.11/src/mod_expire.c 2005-11-03 09:52:13.000000000 +0200
21542 +++ lighttpd-1.4.12/src/mod_expire.c    2006-07-16 00:26:04.000000000 +0300
21543 @@ -12,8 +12,8 @@
21544  #include "stat_cache.h"
21545  
21546  /**
21547 - * this is a expire module for a lighttpd 
21548 - * 
21549 + * this is a expire module for a lighttpd
21550 + *
21551   * set 'Expires:' HTTP Headers on demand
21552   */
21553  
21554 @@ -27,51 +27,51 @@
21555  
21556  typedef struct {
21557         PLUGIN_DATA;
21558 -       
21559 +
21560         buffer *expire_tstmp;
21561 -       
21562 +
21563         plugin_config **config_storage;
21564 -       
21565 -       plugin_config conf; 
21566 +
21567 +       plugin_config conf;
21568  } plugin_data;
21569  
21570  /* init the plugin data */
21571  INIT_FUNC(mod_expire_init) {
21572         plugin_data *p;
21573 -       
21574 +
21575         p = calloc(1, sizeof(*p));
21576 -       
21577 +
21578         p->expire_tstmp = buffer_init();
21579 -       
21580 +
21581         buffer_prepare_copy(p->expire_tstmp, 255);
21582 -       
21583 +
21584         return p;
21585  }
21586  
21587  /* detroy the plugin data */
21588  FREE_FUNC(mod_expire_free) {
21589         plugin_data *p = p_d;
21590 -       
21591 +
21592         UNUSED(srv);
21593  
21594         if (!p) return HANDLER_GO_ON;
21595 -       
21596 +
21597         buffer_free(p->expire_tstmp);
21598 -       
21599 +
21600         if (p->config_storage) {
21601                 size_t i;
21602                 for (i = 0; i < srv->config_context->used; i++) {
21603                         plugin_config *s = p->config_storage[i];
21604 -                       
21605 +
21606                         array_free(s->expire_url);
21607 -                       
21608 +
21609                         free(s);
21610                 }
21611                 free(p->config_storage);
21612         }
21613 -       
21614 +
21615         free(p);
21616 -       
21617 +
21618         return HANDLER_GO_ON;
21619  }
21620  
21621 @@ -79,25 +79,25 @@
21622         char *ts;
21623         int type = -1;
21624         int retts = 0;
21625 -               
21626 +
21627         UNUSED(p);
21628  
21629 -       /* 
21630 +       /*
21631          * parse
21632 -        * 
21633 +        *
21634          * '(access|modification) [plus] {<num> <type>}*'
21635 -        * 
21636 +        *
21637          * e.g. 'access 1 years'
21638          */
21639 -       
21640 +
21641         if (expire->used == 0) {
21642 -               log_error_write(srv, __FILE__, __LINE__, "s", 
21643 +               log_error_write(srv, __FILE__, __LINE__, "s",
21644                                 "empty:");
21645                 return -1;
21646         }
21647 -       
21648 +
21649         ts = expire->ptr;
21650 -       
21651 +
21652         if (0 == strncmp(ts, "access ", 7)) {
21653                 type  = 0;
21654                 ts   += 7;
21655 @@ -110,39 +110,39 @@
21656                                 "invalid <base>:", ts);
21657                 return -1;
21658         }
21659 -       
21660 +
21661         if (0 == strncmp(ts, "plus ", 5)) {
21662                 /* skip the optional plus */
21663                 ts   += 5;
21664         }
21665 -       
21666 +
21667         /* the rest is just <number> (years|months|days|hours|minutes|seconds) */
21668         while (1) {
21669                 char *space, *err;
21670                 int num;
21671 -               
21672 +
21673                 if (NULL == (space = strchr(ts, ' '))) {
21674 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
21675 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
21676                                         "missing space after <num>:", ts);
21677                         return -1;
21678                 }
21679 -               
21680 +
21681                 num = strtol(ts, &err, 10);
21682                 if (*err != ' ') {
21683 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
21684 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
21685                                         "missing <type> after <num>:", ts);
21686                         return -1;
21687                 }
21688 -               
21689 +
21690                 ts = space + 1;
21691 -               
21692 +
21693                 if (NULL != (space = strchr(ts, ' '))) {
21694                         int slen;
21695                         /* */
21696 -                       
21697 +
21698                         slen = space - ts;
21699 -                       
21700 -                       if (slen == 5 && 
21701 +
21702 +                       if (slen == 5 &&
21703                             0 == strncmp(ts, "years", slen)) {
21704                                 num *= 60 * 60 * 24 * 30 * 12;
21705                         } else if (slen == 6 &&
21706 @@ -161,13 +161,13 @@
21707                                    0 == strncmp(ts, "seconds", slen)) {
21708                                 num *= 1;
21709                         } else {
21710 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
21711 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
21712                                                 "unknown type:", ts);
21713                                 return -1;
21714                         }
21715 -                       
21716 +
21717                         retts += num;
21718 -                       
21719 +
21720                         ts = space + 1;
21721                 } else {
21722                         if (0 == strcmp(ts, "years")) {
21723 @@ -183,19 +183,19 @@
21724                         } else if (0 == strcmp(ts, "seconds")) {
21725                                 num *= 1;
21726                         } else {
21727 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
21728 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
21729                                                 "unknown type:", ts);
21730                                 return -1;
21731                         }
21732 -                       
21733 +
21734                         retts += num;
21735 -                       
21736 +
21737                         break;
21738                 }
21739         }
21740 -       
21741 +
21742         if (offset != NULL) *offset = retts;
21743 -       
21744 +
21745         return type;
21746  }
21747  
21748 @@ -205,102 +205,99 @@
21749  SETDEFAULTS_FUNC(mod_expire_set_defaults) {
21750         plugin_data *p = p_d;
21751         size_t i = 0, k;
21752 -       
21753 -       config_values_t cv[] = { 
21754 +
21755 +       config_values_t cv[] = {
21756                 { "expire.url",                 NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
21757                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21758         };
21759 -       
21760 +
21761         if (!p) return HANDLER_ERROR;
21762 -       
21763 +
21764         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21765 -       
21766 +
21767         for (i = 0; i < srv->config_context->used; i++) {
21768                 plugin_config *s;
21769 -               
21770 +
21771                 s = calloc(1, sizeof(plugin_config));
21772                 s->expire_url    = array_init();
21773 -               
21774 +
21775                 cv[0].destination = s->expire_url;
21776 -               
21777 +
21778                 p->config_storage[i] = s;
21779 -       
21780 +
21781                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
21782                         return HANDLER_ERROR;
21783                 }
21784 -       
21785 +
21786                 for (k = 0; k < s->expire_url->used; k++) {
21787                         data_string *ds = (data_string *)s->expire_url->data[k];
21788 -                       
21789 +
21790                         /* parse lines */
21791                         if (-1 == mod_expire_get_offset(srv, p, ds->value, NULL)) {
21792 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
21793 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
21794                                                 "parsing expire.url failed:", ds->value);
21795                                 return HANDLER_ERROR;
21796                         }
21797                 }
21798         }
21799 -       
21800 -       
21801 +
21802 +
21803         return HANDLER_GO_ON;
21804  }
21805  
21806 -#define PATCH(x) \
21807 -       p->conf.x = s->x;
21808  static int mod_expire_patch_connection(server *srv, connection *con, plugin_data *p) {
21809         size_t i, j;
21810         plugin_config *s = p->config_storage[0];
21811 -       
21812 -       PATCH(expire_url);
21813 -       
21814 +
21815 +       PATCH_OPTION(expire_url);
21816 +
21817         /* skip the first, the global context */
21818         for (i = 1; i < srv->config_context->used; i++) {
21819                 data_config *dc = (data_config *)srv->config_context->data[i];
21820                 s = p->config_storage[i];
21821 -               
21822 +
21823                 /* condition didn't match */
21824                 if (!config_check_cond(srv, con, dc)) continue;
21825 -               
21826 +
21827                 /* merge config */
21828                 for (j = 0; j < dc->value->used; j++) {
21829                         data_unset *du = dc->value->data[j];
21830 -                       
21831 +
21832                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("expire.url"))) {
21833 -                               PATCH(expire_url);
21834 +                               PATCH_OPTION(expire_url);
21835                         }
21836                 }
21837         }
21838 -       
21839 +
21840         return 0;
21841  }
21842 -#undef PATCH
21843  
21844  URIHANDLER_FUNC(mod_expire_path_handler) {
21845         plugin_data *p = p_d;
21846         int s_len;
21847         size_t k;
21848 -       
21849 +
21850         if (con->uri.path->used == 0) return HANDLER_GO_ON;
21851 -       
21852 +
21853         mod_expire_patch_connection(srv, con, p);
21854 -       
21855 +
21856         s_len = con->uri.path->used - 1;
21857 -       
21858 +
21859         for (k = 0; k < p->conf.expire_url->used; k++) {
21860                 data_string *ds = (data_string *)p->conf.expire_url->data[k];
21861                 int ct_len = ds->key->used - 1;
21862 -               
21863 +
21864                 if (ct_len > s_len) continue;
21865                 if (ds->key->used == 0) continue;
21866 -               
21867 +
21868                 if (0 == strncmp(con->uri.path->ptr, ds->key->ptr, ct_len)) {
21869                         int ts;
21870                         time_t t;
21871                         size_t len;
21872                         stat_cache_entry *sce = NULL;
21873 -               
21874 +
21875                         stat_cache_get_entry(srv, con, con->physical.path, &sce);
21876 -                       
21877 +
21878                         switch(mod_expire_get_offset(srv, p, ds->value, &ts)) {
21879                         case 0:
21880                                 /* access */
21881 @@ -308,38 +305,38 @@
21882                                 break;
21883                         case 1:
21884                                 /* modification */
21885 -                               
21886 +
21887                                 t = (ts + sce->st.st_mtime);
21888                                 break;
21889                         default:
21890                                 /* -1 is handled at parse-time */
21891                                 break;
21892                         }
21893 -                       
21894 -                       
21895 -                       if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1, 
21896 +
21897 +
21898 +                       if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
21899                                            "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(t))))) {
21900                                 /* could not set expire header, out of mem */
21901 -                               
21902 +
21903                                 return HANDLER_GO_ON;
21904 -                               
21905 +
21906                         }
21907 -                           
21908 +
21909                         p->expire_tstmp->used = len + 1;
21910 -               
21911 -                       /* HTTP/1.0 */  
21912 +
21913 +                       /* HTTP/1.0 */
21914                         response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_BUF_LEN(p->expire_tstmp));
21915  
21916 -                       /* HTTP/1.1 */  
21917 +                       /* HTTP/1.1 */
21918                         buffer_copy_string(p->expire_tstmp, "max-age=");
21919                         buffer_append_long(p->expire_tstmp, ts);
21920 -                       
21921 +
21922                         response_header_overwrite(srv, con, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(p->expire_tstmp));
21923 -                       
21924 +
21925                         return HANDLER_GO_ON;
21926                 }
21927         }
21928 -       
21929 +
21930         /* not found */
21931         return HANDLER_GO_ON;
21932  }
21933 @@ -349,13 +346,13 @@
21934  int mod_expire_plugin_init(plugin *p) {
21935         p->version     = LIGHTTPD_VERSION_ID;
21936         p->name        = buffer_init_string("expire");
21937 -       
21938 +
21939         p->init        = mod_expire_init;
21940         p->handle_subrequest_start = mod_expire_path_handler;
21941         p->set_defaults  = mod_expire_set_defaults;
21942         p->cleanup     = mod_expire_free;
21943 -       
21944 +
21945         p->data        = NULL;
21946 -       
21947 +
21948         return 0;
21949  }
21950 --- ../lighttpd-1.4.11/src/mod_fastcgi.c        2006-03-09 13:18:39.000000000 +0200
21951 +++ lighttpd-1.4.12/src/mod_fastcgi.c   2006-07-19 20:02:55.000000000 +0300
21952 @@ -1,5 +1,4 @@
21953  #include <sys/types.h>
21954 -#include <unistd.h>
21955  #include <errno.h>
21956  #include <fcntl.h>
21957  #include <string.h>
21958 @@ -18,13 +17,14 @@
21959  #include "connections.h"
21960  #include "response.h"
21961  #include "joblist.h"
21962 +#include "status_counter.h"
21963  
21964  #include "plugin.h"
21965  
21966  #include "inet_ntop_cache.h"
21967  #include "stat_cache.h"
21968  
21969 -#include <fastcgi.h>
21970 +#include "fastcgi.h"
21971  #include <stdio.h>
21972  
21973  #ifdef HAVE_SYS_FILIO_H
21974 @@ -32,7 +32,11 @@
21975  #endif
21976  
21977  #include "sys-socket.h"
21978 +#include "sys-files.h"
21979 +#include "sys-strings.h"
21980 +#include "sys-process.h"
21981  
21982 +#include "http_resp.h"
21983  
21984  #ifndef UNIX_PATH_MAX
21985  # define UNIX_PATH_MAX 108
21986 @@ -45,14 +49,13 @@
21987  #include <sys/wait.h>
21988  #endif
21989  
21990 -
21991  /*
21992 - * 
21993 + *
21994   * TODO:
21995 - * 
21996 + *
21997   * - add timeout for a connect to a non-fastcgi process
21998   *   (use state_timestamp + state)
21999 - * 
22000 + *
22001   */
22002  
22003  typedef struct fcgi_proc {
22004 @@ -61,7 +64,7 @@
22005         unsigned port;  /* config.port + pno */
22006  
22007         buffer *connection_name; /* either tcp:<host>:<port> or unix:<socket> for debuggin purposes */
22008 -       
22009 +
22010         pid_t pid;   /* PID of the spawned process (0 if not spawned locally) */
22011  
22012  
22013 @@ -70,20 +73,20 @@
22014         time_t last_used; /* see idle_timeout */
22015         size_t requests;  /* see max_requests */
22016         struct fcgi_proc *prev, *next; /* see first */
22017 -       
22018 +
22019         time_t disabled_until; /* this proc is disabled until, use something else until than */
22020 -       
22021 +
22022         int is_local;
22023  
22024 -       enum { 
22025 +       enum {
22026                 PROC_STATE_UNSET,    /* init-phase */
22027                 PROC_STATE_RUNNING,  /* alive */
22028 -               PROC_STATE_OVERLOADED, /* listen-queue is full, 
22029 +               PROC_STATE_OVERLOADED, /* listen-queue is full,
22030                                           don't send something to this proc for the next 2 seconds */
22031                 PROC_STATE_DIED_WAIT_FOR_PID, /* */
22032                 PROC_STATE_DIED,     /* marked as dead, should be restarted */
22033                 PROC_STATE_KILLED    /* was killed as we don't have the load anymore */
22034 -       } state; 
22035 +       } state;
22036  } fcgi_proc;
22037  
22038  typedef struct {
22039 @@ -94,20 +97,20 @@
22040          * sorted by lowest load
22041          *
22042          * whenever a job is done move it up in the list
22043 -        * until it is sorted, move it down as soon as the 
22044 +        * until it is sorted, move it down as soon as the
22045          * job is started
22046          */
22047 -       fcgi_proc *first; 
22048 -       fcgi_proc *unused_procs; 
22049 +       fcgi_proc *first;
22050 +       fcgi_proc *unused_procs;
22051  
22052 -       /* 
22053 +       /*
22054          * spawn at least min_procs, at max_procs.
22055          *
22056 -        * as soon as the load of the first entry 
22057 +        * as soon as the load of the first entry
22058          * is max_load_per_proc we spawn a new one
22059 -        * and add it to the first entry and give it 
22060 +        * and add it to the first entry and give it
22061          * the load
22062 -        * 
22063 +        *
22064          */
22065  
22066         unsigned short min_procs;
22067 @@ -119,44 +122,44 @@
22068  
22069         /*
22070          * kick the process from the list if it was not
22071 -        * used for idle_timeout until min_procs is 
22072 +        * used for idle_timeout until min_procs is
22073          * reached. this helps to get the processlist
22074          * small again we had a small peak load.
22075          *
22076          */
22077 -       
22078 +
22079         unsigned short idle_timeout;
22080 -       
22081 +
22082         /*
22083          * time after a disabled remote connection is tried to be re-enabled
22084 -        * 
22085 -        * 
22086 +        *
22087 +        *
22088          */
22089 -       
22090 +
22091         unsigned short disable_time;
22092  
22093         /*
22094          * same fastcgi processes get a little bit larger
22095 -        * than wanted. max_requests_per_proc kills a 
22096 +        * than wanted. max_requests_per_proc kills a
22097          * process after a number of handled requests.
22098          *
22099          */
22100         size_t max_requests_per_proc;
22101 -       
22102 +
22103  
22104         /* config */
22105  
22106 -       /* 
22107 -        * host:port 
22108 +       /*
22109 +        * host:port
22110          *
22111 -        * if host is one of the local IP adresses the 
22112 +        * if host is one of the local IP adresses the
22113          * whole connection is local
22114          *
22115          * if tcp/ip should be used host AND port have
22116 -        * to be specified 
22117 -        * 
22118 -        */ 
22119 -       buffer *host; 
22120 +        * to be specified
22121 +        *
22122 +        */
22123 +       buffer *host;
22124         unsigned short port;
22125  
22126         /*
22127 @@ -169,7 +172,7 @@
22128          */
22129         buffer *unixsocket;
22130  
22131 -       /* if socket is local we can start the fastcgi 
22132 +       /* if socket is local we can start the fastcgi
22133          * process ourself
22134          *
22135          * bin-path is the path to the binary
22136 @@ -177,19 +180,19 @@
22137          * check min_procs and max_procs for the number
22138          * of process to start-up
22139          */
22140 -       buffer *bin_path; 
22141 -       
22142 -       /* bin-path is set bin-environment is taken to 
22143 +       buffer *bin_path;
22144 +
22145 +       /* bin-path is set bin-environment is taken to
22146          * create the environement before starting the
22147          * FastCGI process
22148 -        * 
22149 +        *
22150          */
22151         array *bin_env;
22152 -       
22153 +
22154         array *bin_env_copy;
22155 -       
22156 +
22157         /*
22158 -        * docroot-translation between URL->phys and the 
22159 +        * docroot-translation between URL->phys and the
22160          * remote host
22161          *
22162          * reasons:
22163 @@ -208,7 +211,7 @@
22164         unsigned short mode;
22165  
22166         /*
22167 -        * check_local tell you if the phys file is stat()ed 
22168 +        * check_local tell you if the phys file is stat()ed
22169          * or not. FastCGI doesn't care if the service is
22170          * remote. If the web-server side doesn't contain
22171          * the fastcgi-files we should not stat() for them
22172 @@ -218,11 +221,11 @@
22173  
22174         /*
22175          * append PATH_INFO to SCRIPT_FILENAME
22176 -        * 
22177 +        *
22178          * php needs this if cgi.fix_pathinfo is provied
22179 -        * 
22180 +        *
22181          */
22182 -       
22183 +
22184         unsigned short break_scriptfilename_for_php;
22185  
22186         /*
22187 @@ -231,12 +234,12 @@
22188          *
22189          */
22190         unsigned short allow_xsendfile;
22191 -               
22192 +
22193         ssize_t load; /* replace by host->load */
22194  
22195         size_t max_id; /* corresponds most of the time to
22196         num_procs.
22197 -       
22198 +
22199         only if a process is killed max_id waits for the process itself
22200         to die and decrements its afterwards */
22201  
22202 @@ -245,17 +248,17 @@
22203  
22204  /*
22205   * one extension can have multiple hosts assigned
22206 - * one host can spawn additional processes on the same 
22207 + * one host can spawn additional processes on the same
22208   *   socket (if we control it)
22209   *
22210   * ext -> host -> procs
22211   *    1:n     1:n
22212   *
22213 - * if the fastcgi process is remote that whole goes down 
22214 + * if the fastcgi process is remote that whole goes down
22215   * to
22216   *
22217   * ext -> host -> procs
22218 - *    1:n     1:1 
22219 + *    1:n     1:1
22220   *
22221   * in case of PHP and FCGI_CHILDREN we have again a procs
22222   * but we don't control it directly.
22223 @@ -268,7 +271,7 @@
22224         int note_is_sent;
22225  
22226         fcgi_extension_host **hosts;
22227 -       
22228 +
22229         size_t used;
22230         size_t size;
22231  } fcgi_extension;
22232 @@ -282,10 +285,10 @@
22233  
22234  
22235  typedef struct {
22236 -       fcgi_exts *exts; 
22237 +       fcgi_exts *exts;
22238  
22239         array *ext_mapping;
22240 -       
22241 +
22242         int debug;
22243  } plugin_config;
22244  
22245 @@ -297,7 +300,7 @@
22246  
22247  typedef struct {
22248         char **ptr;
22249 -       
22250 +
22251         size_t size;
22252         size_t used;
22253  } char_array;
22254 @@ -306,55 +309,54 @@
22255  typedef struct {
22256         PLUGIN_DATA;
22257         buffer_uint fcgi_request_id;
22258 -       
22259 +
22260         buffer *fcgi_env;
22261 -       
22262 +
22263         buffer *path;
22264 -       buffer *parse_response;
22265  
22266         buffer *statuskey;
22267 -       
22268 +
22269 +       http_resp *resp;
22270 +
22271         plugin_config **config_storage;
22272 -       
22273 +
22274         plugin_config conf; /* this is only used as long as no handler_ctx is setup */
22275  } plugin_data;
22276  
22277  /* connection specific data */
22278 -typedef enum { 
22279 +typedef enum {
22280         FCGI_STATE_UNSET,
22281 -       FCGI_STATE_INIT, 
22282 -       FCGI_STATE_CONNECT_DELAYED, 
22283 -       FCGI_STATE_PREPARE_WRITE, 
22284 -       FCGI_STATE_WRITE, 
22285 -       FCGI_STATE_READ 
22286 +       FCGI_STATE_INIT,
22287 +       FCGI_STATE_CONNECT_DELAYED,
22288 +       FCGI_STATE_PREPARE_WRITE,
22289 +       FCGI_STATE_WRITE,
22290 +       FCGI_STATE_READ
22291  } fcgi_connection_state_t;
22292  
22293  typedef struct {
22294         fcgi_proc *proc;
22295         fcgi_extension_host *host;
22296         fcgi_extension *ext;
22297 -       
22298 +
22299         fcgi_connection_state_t state;
22300         time_t   state_timestamp;
22301 -       
22302 +
22303         int      reconnects; /* number of reconnect attempts */
22304 -       
22305 -       chunkqueue *rb; /* read queue */
22306 +
22307 +       chunkqueue *rb; /* the raw fcgi read-queue */
22308 +       chunkqueue *http_rb; /* the decoded read-queue for http-parsing */
22309         chunkqueue *wb; /* write queue */
22310 -       
22311 -       buffer   *response_header;
22312 -       
22313 +
22314         size_t    request_id;
22315 -       int       fd;        /* fd to the fastcgi process */
22316 -       int       fde_ndx;   /* index into the fd-event buffer */
22317 +       iosocket *sock;
22318  
22319         pid_t     pid;
22320         int       got_proc;
22321  
22322         int       send_content_body;
22323 -       
22324 +
22325         plugin_config conf;
22326 -       
22327 +
22328         connection *remote_conn;  /* dumb pointer */
22329         plugin_data *plugin_data; /* dumb pointer */
22330  } handler_ctx;
22331 @@ -363,49 +365,6 @@
22332  /* ok, we need a prototype */
22333  static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents);
22334  
22335 -data_integer *status_counter_get_counter(server *srv, const char *s, size_t len) {
22336 -       data_integer *di;
22337 -
22338 -       if (NULL == (di = (data_integer *)array_get_element(srv->status, s))) {
22339 -               /* not found, create it */
22340 -
22341 -               if (NULL == (di = (data_integer *)array_get_unused_element(srv->status, TYPE_INTEGER))) {
22342 -                       di = data_integer_init();
22343 -               }
22344 -               buffer_copy_string_len(di->key, s, len);
22345 -               di->value = 0;
22346 -
22347 -               array_insert_unique(srv->status, (data_unset *)di);
22348 -       }
22349 -       return di;
22350 -}
22351 -
22352 -/* dummies of the statistic framework functions 
22353 - * they will be moved to a statistics.c later */
22354 -int status_counter_inc(server *srv, const char *s, size_t len) {
22355 -       data_integer *di = status_counter_get_counter(srv, s, len);
22356 -
22357 -       di->value++;
22358 -
22359 -       return 0;
22360 -}
22361 -
22362 -int status_counter_dec(server *srv, const char *s, size_t len) {
22363 -       data_integer *di = status_counter_get_counter(srv, s, len);
22364 -
22365 -       if (di->value > 0) di->value--;
22366 -
22367 -       return 0;
22368 -}
22369 -
22370 -int status_counter_set(server *srv, const char *s, size_t len, int val) {
22371 -       data_integer *di = status_counter_get_counter(srv, s, len);
22372 -
22373 -       di->value = val;
22374 -
22375 -       return 0;
22376 -}
22377 -
22378  int fastcgi_status_copy_procname(buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
22379         buffer_copy_string(b, "fastcgi.backend.");
22380         buffer_append_string_buffer(b, host->id);
22381 @@ -421,7 +380,7 @@
22382  #define CLEAN(x) \
22383         fastcgi_status_copy_procname(b, host, proc); \
22384         buffer_append_string(b, x); \
22385 -       status_counter_set(srv, CONST_BUF_LEN(b), 0);
22386 +       status_counter_set(CONST_BUF_LEN(b), 0);
22387  
22388         CLEAN(".disabled");
22389         CLEAN(".died");
22390 @@ -429,42 +388,39 @@
22391         CLEAN(".connected");
22392         CLEAN(".load");
22393  
22394 -#undef CLEAN   
22395 +#undef CLEAN
22396  
22397  #define CLEAN(x) \
22398         fastcgi_status_copy_procname(b, host, NULL); \
22399         buffer_append_string(b, x); \
22400 -       status_counter_set(srv, CONST_BUF_LEN(b), 0);
22401 +       status_counter_set(CONST_BUF_LEN(b), 0);
22402  
22403         CLEAN(".load");
22404  
22405 -#undef CLEAN   
22406 +#undef CLEAN
22407  
22408         return 0;
22409  }
22410  
22411  static handler_ctx * handler_ctx_init() {
22412         handler_ctx * hctx;
22413 -       
22414 +
22415         hctx = calloc(1, sizeof(*hctx));
22416         assert(hctx);
22417 -       
22418 -       hctx->fde_ndx = -1;
22419 -       
22420 -       hctx->response_header = buffer_init();
22421 -       
22422 +
22423         hctx->request_id = 0;
22424         hctx->state = FCGI_STATE_INIT;
22425         hctx->proc = NULL;
22426 -       
22427 -       hctx->fd = -1;
22428 -       
22429 +
22430 +       hctx->sock = iosocket_init();
22431 +
22432         hctx->reconnects = 0;
22433         hctx->send_content_body = 1;
22434  
22435         hctx->rb = chunkqueue_init();
22436 +       hctx->http_rb = chunkqueue_init();
22437         hctx->wb = chunkqueue_init();
22438 -       
22439 +
22440         return hctx;
22441  }
22442  
22443 @@ -473,12 +429,13 @@
22444                 hctx->host->load--;
22445                 hctx->host = NULL;
22446         }
22447 -       
22448 -       buffer_free(hctx->response_header);
22449  
22450         chunkqueue_free(hctx->rb);
22451 +       chunkqueue_free(hctx->http_rb);
22452         chunkqueue_free(hctx->wb);
22453  
22454 +       iosocket_free(hctx->sock);
22455 +
22456         free(hctx);
22457  }
22458  
22459 @@ -488,21 +445,21 @@
22460         f = calloc(1, sizeof(*f));
22461         f->unixsocket = buffer_init();
22462         f->connection_name = buffer_init();
22463 -       
22464 +
22465         f->prev = NULL;
22466         f->next = NULL;
22467 -       
22468 +
22469         return f;
22470  }
22471  
22472  void fastcgi_process_free(fcgi_proc *f) {
22473         if (!f) return;
22474 -       
22475 +
22476         fastcgi_process_free(f->next);
22477 -       
22478 +
22479         buffer_free(f->unixsocket);
22480         buffer_free(f->connection_name);
22481 -       
22482 +
22483         free(f);
22484  }
22485  
22486 @@ -519,13 +476,13 @@
22487         f->bin_env = array_init();
22488         f->bin_env_copy = array_init();
22489         f->strip_request_uri = buffer_init();
22490 -       
22491 +
22492         return f;
22493  }
22494  
22495  void fastcgi_host_free(fcgi_extension_host *h) {
22496         if (!h) return;
22497 -       
22498 +
22499         buffer_free(h->id);
22500         buffer_free(h->host);
22501         buffer_free(h->unixsocket);
22502 @@ -534,49 +491,49 @@
22503         buffer_free(h->strip_request_uri);
22504         array_free(h->bin_env);
22505         array_free(h->bin_env_copy);
22506 -       
22507 +
22508         fastcgi_process_free(h->first);
22509         fastcgi_process_free(h->unused_procs);
22510 -       
22511 +
22512         free(h);
22513 -       
22514 +
22515  }
22516  
22517  fcgi_exts *fastcgi_extensions_init() {
22518         fcgi_exts *f;
22519  
22520         f = calloc(1, sizeof(*f));
22521 -       
22522 +
22523         return f;
22524  }
22525  
22526  void fastcgi_extensions_free(fcgi_exts *f) {
22527         size_t i;
22528 -       
22529 +
22530         if (!f) return;
22531 -       
22532 +
22533         for (i = 0; i < f->used; i++) {
22534                 fcgi_extension *fe;
22535                 size_t j;
22536 -               
22537 +
22538                 fe = f->exts[i];
22539 -               
22540 +
22541                 for (j = 0; j < fe->used; j++) {
22542                         fcgi_extension_host *h;
22543 -                       
22544 +
22545                         h = fe->hosts[j];
22546 -                       
22547 +
22548                         fastcgi_host_free(h);
22549                 }
22550 -               
22551 +
22552                 buffer_free(fe->key);
22553                 free(fe->hosts);
22554 -               
22555 +
22556                 free(fe);
22557         }
22558 -       
22559 +
22560         free(f->exts);
22561 -       
22562 +
22563         free(f);
22564  }
22565  
22566 @@ -625,24 +582,25 @@
22567                 assert(fe->hosts);
22568         }
22569  
22570 -       fe->hosts[fe->used++] = fh; 
22571 +       fe->hosts[fe->used++] = fh;
22572  
22573         return 0;
22574 -       
22575 +
22576  }
22577  
22578  INIT_FUNC(mod_fastcgi_init) {
22579         plugin_data *p;
22580 -       
22581 +
22582         p = calloc(1, sizeof(*p));
22583 -       
22584 +
22585         p->fcgi_env = buffer_init();
22586 -       
22587 +
22588         p->path = buffer_init();
22589 -       p->parse_response = buffer_init();
22590 +
22591 +       p->resp = http_response_init();
22592  
22593         p->statuskey = buffer_init();
22594 -       
22595 +
22596         return p;
22597  }
22598  
22599 @@ -650,81 +608,82 @@
22600  FREE_FUNC(mod_fastcgi_free) {
22601         plugin_data *p = p_d;
22602         buffer_uint *r = &(p->fcgi_request_id);
22603 -       
22604 +
22605         UNUSED(srv);
22606  
22607         if (r->ptr) free(r->ptr);
22608 -       
22609 +
22610         buffer_free(p->fcgi_env);
22611         buffer_free(p->path);
22612 -       buffer_free(p->parse_response);
22613         buffer_free(p->statuskey);
22614 -       
22615 +
22616 +       http_response_free(p->resp);
22617 +
22618         if (p->config_storage) {
22619                 size_t i, j, n;
22620                 for (i = 0; i < srv->config_context->used; i++) {
22621                         plugin_config *s = p->config_storage[i];
22622                         fcgi_exts *exts;
22623 -                       
22624 +
22625                         if (!s) continue;
22626 -                       
22627 +
22628                         exts = s->exts;
22629  
22630                         for (j = 0; j < exts->used; j++) {
22631                                 fcgi_extension *ex;
22632 -                               
22633 +
22634                                 ex = exts->exts[j];
22635 -                               
22636 +
22637                                 for (n = 0; n < ex->used; n++) {
22638                                         fcgi_proc *proc;
22639                                         fcgi_extension_host *host;
22640 -                                       
22641 +
22642                                         host = ex->hosts[n];
22643 -                                       
22644 +
22645                                         for (proc = host->first; proc; proc = proc->next) {
22646                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
22647 -                                               
22648 -                                               if (proc->is_local && 
22649 +
22650 +                                               if (proc->is_local &&
22651                                                     !buffer_is_empty(proc->unixsocket)) {
22652                                                         unlink(proc->unixsocket->ptr);
22653                                                 }
22654                                         }
22655 -                                       
22656 +
22657                                         for (proc = host->unused_procs; proc; proc = proc->next) {
22658                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
22659 -                                               
22660 -                                               if (proc->is_local && 
22661 +
22662 +                                               if (proc->is_local &&
22663                                                     !buffer_is_empty(proc->unixsocket)) {
22664                                                         unlink(proc->unixsocket->ptr);
22665                                                 }
22666                                         }
22667                                 }
22668                         }
22669 -                       
22670 +
22671                         fastcgi_extensions_free(s->exts);
22672                         array_free(s->ext_mapping);
22673 -                       
22674 +
22675                         free(s);
22676                 }
22677                 free(p->config_storage);
22678         }
22679 -       
22680 +
22681         free(p);
22682 -       
22683 +
22684         return HANDLER_GO_ON;
22685  }
22686  
22687  static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
22688         char *dst;
22689 -       
22690 +
22691         if (!key || !val) return -1;
22692 -       
22693 +
22694         dst = malloc(key_len + val_len + 3);
22695         memcpy(dst, key, key_len);
22696         dst[key_len] = '=';
22697         /* add the \0 from the value */
22698         memcpy(dst + key_len + 1, val, val_len + 1);
22699 -       
22700 +
22701         if (env->size == 0) {
22702                 env->size = 16;
22703                 env->ptr = malloc(env->size * sizeof(*env->ptr));
22704 @@ -732,9 +691,9 @@
22705                 env->size += 16;
22706                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
22707         }
22708 -       
22709 +
22710         env->ptr[env->used++] = dst;
22711 -       
22712 +
22713         return 0;
22714  }
22715  
22716 @@ -753,15 +712,15 @@
22717                         if (env->size == 0) {
22718                                 env->size = 16;
22719                                 env->ptr = malloc(env->size * sizeof(*env->ptr));
22720 -                       } else if (env->size == env->used) { 
22721 +                       } else if (env->size == env->used) {
22722                                 env->size += 16;
22723                                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
22724                         }
22725 -                       
22726 +
22727                         b->ptr[i] = '\0';
22728  
22729                         env->ptr[env->used++] = start;
22730 -                       
22731 +
22732                         start = b->ptr + i + 1;
22733                         break;
22734                 default:
22735 @@ -794,7 +753,7 @@
22736         return 0;
22737  }
22738  
22739 -static int fcgi_spawn_connection(server *srv, 
22740 +static int fcgi_spawn_connection(server *srv,
22741                                  plugin_data *p,
22742                                  fcgi_extension_host *host,
22743                                  fcgi_proc *proc) {
22744 @@ -806,31 +765,27 @@
22745  #endif
22746         struct sockaddr_in fcgi_addr_in;
22747         struct sockaddr *fcgi_addr;
22748 -       
22749 +
22750         socklen_t servlen;
22751 -       
22752 +
22753  #ifndef HAVE_FORK
22754         return -1;
22755  #endif
22756 -       
22757 +
22758         if (p->conf.debug) {
22759                 log_error_write(srv, __FILE__, __LINE__, "sdb",
22760                                 "new proc, socket:", proc->port, proc->unixsocket);
22761         }
22762 -               
22763 +
22764         if (!buffer_is_empty(proc->unixsocket)) {
22765                 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
22766 -               
22767 +
22768  #ifdef HAVE_SYS_UN_H
22769                 fcgi_addr_un.sun_family = AF_UNIX;
22770                 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
22771 -               
22772 -#ifdef SUN_LEN
22773 +
22774                 servlen = SUN_LEN(&fcgi_addr_un);
22775 -#else
22776 -               /* stevens says: */
22777 -               servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
22778 -#endif
22779 +
22780                 socket_type = AF_UNIX;
22781                 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
22782  
22783 @@ -844,108 +799,108 @@
22784  #endif
22785         } else {
22786                 fcgi_addr_in.sin_family = AF_INET;
22787 -               
22788 +
22789                 if (buffer_is_empty(host->host)) {
22790                         fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
22791                 } else {
22792                         struct hostent *he;
22793 -                       
22794 +
22795                         /* set a usefull default */
22796                         fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
22797 -                       
22798 -                       
22799 +
22800 +
22801                         if (NULL == (he = gethostbyname(host->host->ptr))) {
22802 -                               log_error_write(srv, __FILE__, __LINE__, 
22803 -                                               "sdb", "gethostbyname failed: ", 
22804 +                               log_error_write(srv, __FILE__, __LINE__,
22805 +                                               "sdb", "gethostbyname failed: ",
22806                                                 h_errno, host->host);
22807                                 return -1;
22808                         }
22809 -                       
22810 +
22811                         if (he->h_addrtype != AF_INET) {
22812                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
22813                                 return -1;
22814                         }
22815 -                       
22816 +
22817                         if (he->h_length != sizeof(struct in_addr)) {
22818                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
22819                                 return -1;
22820                         }
22821 -                       
22822 +
22823                         memcpy(&(fcgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
22824 -                       
22825 +
22826                 }
22827                 fcgi_addr_in.sin_port = htons(proc->port);
22828                 servlen = sizeof(fcgi_addr_in);
22829 -               
22830 +
22831                 socket_type = AF_INET;
22832                 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
22833 -               
22834 +
22835                 buffer_copy_string(proc->connection_name, "tcp:");
22836                 buffer_append_string_buffer(proc->connection_name, host->host);
22837                 buffer_append_string(proc->connection_name, ":");
22838                 buffer_append_long(proc->connection_name, proc->port);
22839         }
22840 -       
22841 +
22842         if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
22843 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
22844 +               log_error_write(srv, __FILE__, __LINE__, "ss",
22845                                 "failed:", strerror(errno));
22846                 return -1;
22847         }
22848 -       
22849 +
22850         if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
22851                 /* server is not up, spawn in  */
22852                 pid_t child;
22853                 int val;
22854 -               
22855 -               if (errno != ENOENT && 
22856 +
22857 +               if (errno != ENOENT &&
22858                     !buffer_is_empty(proc->unixsocket)) {
22859                         unlink(proc->unixsocket->ptr);
22860                 }
22861 -               
22862 +
22863                 close(fcgi_fd);
22864 -               
22865 +
22866                 /* reopen socket */
22867                 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
22868 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
22869 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
22870                                 "socket failed:", strerror(errno));
22871                         return -1;
22872                 }
22873 -               
22874 +
22875                 val = 1;
22876                 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
22877 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
22878 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
22879                                         "socketsockopt failed:", strerror(errno));
22880                         return -1;
22881                 }
22882 -               
22883 +
22884                 /* create socket */
22885                 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
22886 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
22887 -                               "bind failed for:", 
22888 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
22889 +                               "bind failed for:",
22890                                 proc->connection_name,
22891                                 strerror(errno));
22892                         return -1;
22893                 }
22894 -               
22895 +
22896                 if (-1 == listen(fcgi_fd, 1024)) {
22897 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
22898 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
22899                                 "listen failed:", strerror(errno));
22900                         return -1;
22901                 }
22902 -               
22903 -#ifdef HAVE_FORK       
22904 +
22905 +#ifndef _WIN32
22906                 switch ((child = fork())) {
22907                 case 0: {
22908                         size_t i = 0;
22909                         char *c;
22910                         char_array env;
22911                         char_array arg;
22912 -                       
22913 +
22914                         /* create environment */
22915                         env.ptr = NULL;
22916                         env.size = 0;
22917                         env.used = 0;
22918 -                       
22919 +
22920                         arg.ptr = NULL;
22921                         arg.size = 0;
22922                         arg.used = 0;
22923 @@ -955,18 +910,18 @@
22924                                 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
22925                                 close(fcgi_fd);
22926                         }
22927 -                       
22928 +
22929                         /* we don't need the client socket */
22930                         for (i = 3; i < 256; i++) {
22931                                 close(i);
22932                         }
22933 -                       
22934 +
22935                         /* build clean environment */
22936                         if (host->bin_env_copy->used) {
22937                                 for (i = 0; i < host->bin_env_copy->used; i++) {
22938                                         data_string *ds = (data_string *)host->bin_env_copy->data[i];
22939                                         char *ge;
22940 -                                       
22941 +
22942                                         if (NULL != (ge = getenv(ds->value->ptr))) {
22943                                                 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
22944                                         }
22945 @@ -974,39 +929,39 @@
22946                         } else {
22947                                 for (i = 0; environ[i]; i++) {
22948                                         char *eq;
22949 -                                       
22950 +
22951                                         if (NULL != (eq = strchr(environ[i], '='))) {
22952                                                 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
22953                                         }
22954                                 }
22955                         }
22956 -                       
22957 +
22958                         /* create environment */
22959                         for (i = 0; i < host->bin_env->used; i++) {
22960                                 data_string *ds = (data_string *)host->bin_env->data[i];
22961 -                               
22962 +
22963                                 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
22964                         }
22965 -                       
22966 +
22967                         for (i = 0; i < env.used; i++) {
22968                                 /* search for PHP_FCGI_CHILDREN */
22969                                 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
22970                         }
22971 -                       
22972 +
22973                         /* not found, add a default */
22974                         if (i == env.used) {
22975                                 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
22976                         }
22977 -                       
22978 +
22979                         env.ptr[env.used] = NULL;
22980  
22981                         parse_binpath(&arg, host->bin_path);
22982 -                       
22983 +
22984                         /* chdir into the base of the bin-path,
22985                          * search for the last / */
22986                         if (NULL != (c = strrchr(arg.ptr[0], '/'))) {
22987                                 *c = '\0';
22988 -                       
22989 +
22990                                 /* change to the physical directory */
22991                                 if (-1 == chdir(arg.ptr[0])) {
22992                                         *c = '/';
22993 @@ -1018,12 +973,12 @@
22994  
22995                         /* exec the cgi */
22996                         execve(arg.ptr[0], arg.ptr, env.ptr);
22997 -                       
22998 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
22999 +
23000 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
23001                                         "execve failed for:", host->bin_path, strerror(errno));
23002 -                       
23003 +
23004                         exit(errno);
23005 -                       
23006 +
23007                         break;
23008                 }
23009                 case -1:
23010 @@ -1031,17 +986,17 @@
23011                         break;
23012                 default:
23013                         /* father */
23014 -                       
23015 +
23016                         /* wait */
23017                         select(0, NULL, NULL, NULL, &tv);
23018 -                       
23019 +
23020                         switch (waitpid(child, &status, WNOHANG)) {
23021                         case 0:
23022                                 /* child still running after timeout, good */
23023                                 break;
23024                         case -1:
23025                                 /* no PID found ? should never happen */
23026 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
23027 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
23028                                                 "pid not found:", strerror(errno));
23029                                 return -1;
23030                         default:
23031 @@ -1049,10 +1004,10 @@
23032                                                 "the fastcgi-backend", host->bin_path, "failed to start:");
23033                                 /* the child should not terminate at all */
23034                                 if (WIFEXITED(status)) {
23035 -                                       log_error_write(srv, __FILE__, __LINE__, "sdb", 
23036 -                                                       "child exited with status", 
23037 +                                       log_error_write(srv, __FILE__, __LINE__, "sdb",
23038 +                                                       "child exited with status",
23039                                                         WEXITSTATUS(status), host->bin_path);
23040 -                                       log_error_write(srv, __FILE__, __LINE__, "s", 
23041 +                                       log_error_write(srv, __FILE__, __LINE__, "s",
23042                                                         "if you try do run PHP as FastCGI backend make sure you use the FastCGI enabled version.\n"
23043                                                         "You can find out if it is the right one by executing 'php -v' and it should display '(cgi-fcgi)' "
23044                                                         "in the output, NOT (cgi) NOR (cli)\n"
23045 @@ -1060,8 +1015,8 @@
23046                                         log_error_write(srv, __FILE__, __LINE__, "s",
23047                                                         "If this is PHP on Gentoo add fastcgi to the USE flags");
23048                                 } else if (WIFSIGNALED(status)) {
23049 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
23050 -                                                       "terminated by signal:", 
23051 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
23052 +                                                       "terminated by signal:",
23053                                                         WTERMSIG(status));
23054  
23055                                         if (WTERMSIG(status) == 11) {
23056 @@ -1071,8 +1026,8 @@
23057                                                                 "If this is PHP try to remove the byte-code caches for now and try again.");
23058                                         }
23059                                 } else {
23060 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
23061 -                                                       "child died somehow:", 
23062 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
23063 +                                                       "child died somehow:",
23064                                                         status);
23065                                 }
23066                                 return -1;
23067 @@ -1082,26 +1037,26 @@
23068                         proc->pid = child;
23069                         proc->last_used = srv->cur_ts;
23070                         proc->is_local = 1;
23071 -                                               
23072 +
23073                         break;
23074                 }
23075  #endif
23076         } else {
23077                 proc->is_local = 0;
23078                 proc->pid = 0;
23079 -               
23080 +
23081                 if (p->conf.debug) {
23082                         log_error_write(srv, __FILE__, __LINE__, "sb",
23083                                         "(debug) socket is already used, won't spawn:",
23084                                         proc->connection_name);
23085                 }
23086         }
23087 -       
23088 +
23089         proc->state = PROC_STATE_RUNNING;
23090         host->active_procs++;
23091 -       
23092 +
23093         close(fcgi_fd);
23094 -       
23095 +
23096         return 0;
23097  }
23098  
23099 @@ -1111,93 +1066,93 @@
23100         data_unset *du;
23101         size_t i = 0;
23102         buffer *fcgi_mode = buffer_init();
23103 -       
23104 -       config_values_t cv[] = { 
23105 +
23106 +       config_values_t cv[] = {
23107                 { "fastcgi.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
23108                 { "fastcgi.debug",               NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
23109                 { "fastcgi.map-extensions",      NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
23110                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
23111         };
23112 -       
23113 +
23114         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
23115 -       
23116 +
23117         for (i = 0; i < srv->config_context->used; i++) {
23118                 plugin_config *s;
23119                 array *ca;
23120 -               
23121 +
23122                 s = malloc(sizeof(plugin_config));
23123                 s->exts          = fastcgi_extensions_init();
23124                 s->debug         = 0;
23125                 s->ext_mapping   = array_init();
23126 -               
23127 +
23128                 cv[0].destination = s->exts;
23129                 cv[1].destination = &(s->debug);
23130                 cv[2].destination = s->ext_mapping;
23131 -               
23132 +
23133                 p->config_storage[i] = s;
23134                 ca = ((data_config *)srv->config_context->data[i])->value;
23135 -       
23136 +
23137                 if (0 != config_insert_values_global(srv, ca, cv)) {
23138                         return HANDLER_ERROR;
23139                 }
23140 -               
23141 -               /* 
23142 +
23143 +               /*
23144                  * <key> = ( ... )
23145                  */
23146 -               
23147 +
23148                 if (NULL != (du = array_get_element(ca, "fastcgi.server"))) {
23149                         size_t j;
23150                         data_array *da = (data_array *)du;
23151 -                       
23152 +
23153                         if (du->type != TYPE_ARRAY) {
23154 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
23155 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
23156                                                 "unexpected type for key: ", "fastcgi.server", "array of strings");
23157 -                               
23158 +
23159                                 return HANDLER_ERROR;
23160                         }
23161 -                       
23162 -                       
23163 -                       /* 
23164 -                        * fastcgi.server = ( "<ext>" => ( ... ), 
23165 +
23166 +
23167 +                       /*
23168 +                        * fastcgi.server = ( "<ext>" => ( ... ),
23169                          *                    "<ext>" => ( ... ) )
23170                          */
23171 -                       
23172 +
23173                         for (j = 0; j < da->value->used; j++) {
23174                                 size_t n;
23175                                 data_array *da_ext = (data_array *)da->value->data[j];
23176 -                               
23177 +
23178                                 if (da->value->data[j]->type != TYPE_ARRAY) {
23179 -                                       log_error_write(srv, __FILE__, __LINE__, "sssbs", 
23180 -                                                       "unexpected type for key: ", "fastcgi.server", 
23181 +                                       log_error_write(srv, __FILE__, __LINE__, "sssbs",
23182 +                                                       "unexpected type for key: ", "fastcgi.server",
23183                                                         "[", da->value->data[j]->key, "](string)");
23184 -                                       
23185 +
23186                                         return HANDLER_ERROR;
23187                                 }
23188 -                               
23189 -                               /* 
23190 -                                * da_ext->key == name of the extension 
23191 +
23192 +                               /*
23193 +                                * da_ext->key == name of the extension
23194                                  */
23195 -                               
23196 -                               /* 
23197 -                                * fastcgi.server = ( "<ext>" => 
23198 -                                *                     ( "<host>" => ( ... ), 
23199 +
23200 +                               /*
23201 +                                * fastcgi.server = ( "<ext>" =>
23202 +                                *                     ( "<host>" => ( ... ),
23203                                  *                       "<host>" => ( ... )
23204 -                                *                     ), 
23205 +                                *                     ),
23206                                  *                    "<ext>" => ... )
23207                                  */
23208 -                                       
23209 +
23210                                 for (n = 0; n < da_ext->value->used; n++) {
23211                                         data_array *da_host = (data_array *)da_ext->value->data[n];
23212 -                                       
23213 +
23214                                         fcgi_extension_host *host;
23215 -                                       
23216 -                                       config_values_t fcv[] = { 
23217 +
23218 +                                       config_values_t fcv[] = {
23219                                                 { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
23220                                                 { "docroot",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
23221                                                 { "mode",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
23222                                                 { "socket",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
23223                                                 { "bin-path",          NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 4 */
23224 -                                               
23225 +
23226                                                 { "check-local",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 5 */
23227                                                 { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 6 */
23228                                                 { "min-procs-not-working",         NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 7 this is broken for now */
23229 @@ -1205,28 +1160,28 @@
23230                                                 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 9 */
23231                                                 { "idle-timeout",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 10 */
23232                                                 { "disable-time",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 11 */
23233 -                                               
23234 +
23235                                                 { "bin-environment",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 12 */
23236                                                 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },     /* 13 */
23237 -                                               
23238 +
23239                                                 { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },  /* 14 */
23240                                                 { "allow-x-send-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 15 */
23241                                                 { "strip-request-uri",  NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 16 */
23242 -                                               
23243 +
23244                                                 { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
23245                                         };
23246 -                                       
23247 +
23248                                         if (da_host->type != TYPE_ARRAY) {
23249 -                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS", 
23250 -                                                               "unexpected type for key:", 
23251 -                                                               "fastcgi.server", 
23252 +                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS",
23253 +                                                               "unexpected type for key:",
23254 +                                                               "fastcgi.server",
23255                                                                 "[", da_host->key, "](string)");
23256 -                                               
23257 +
23258                                                 return HANDLER_ERROR;
23259                                         }
23260 -                                       
23261 +
23262                                         host = fastcgi_host_init();
23263 -                                       
23264 +
23265                                         buffer_copy_string_buffer(host->id, da_host->key);
23266  
23267                                         host->check_local  = 1;
23268 @@ -1238,13 +1193,13 @@
23269                                         host->disable_time = 60;
23270                                         host->break_scriptfilename_for_php = 0;
23271                                         host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
23272 -                                       
23273 +
23274                                         fcv[0].destination = host->host;
23275                                         fcv[1].destination = host->docroot;
23276                                         fcv[2].destination = fcgi_mode;
23277                                         fcv[3].destination = host->unixsocket;
23278                                         fcv[4].destination = host->bin_path;
23279 -                                       
23280 +
23281                                         fcv[5].destination = &(host->check_local);
23282                                         fcv[6].destination = &(host->port);
23283                                         fcv[7].destination = &(host->min_procs);
23284 @@ -1252,35 +1207,35 @@
23285                                         fcv[9].destination = &(host->max_load_per_proc);
23286                                         fcv[10].destination = &(host->idle_timeout);
23287                                         fcv[11].destination = &(host->disable_time);
23288 -                                       
23289 +
23290                                         fcv[12].destination = host->bin_env;
23291                                         fcv[13].destination = host->bin_env_copy;
23292                                         fcv[14].destination = &(host->break_scriptfilename_for_php);
23293                                         fcv[15].destination = &(host->allow_xsendfile);
23294                                         fcv[16].destination = host->strip_request_uri;
23295 -                                       
23296 +
23297                                         if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
23298                                                 return HANDLER_ERROR;
23299                                         }
23300 -                                                       
23301 -                                       if ((!buffer_is_empty(host->host) || host->port) && 
23302 +
23303 +                                       if ((!buffer_is_empty(host->host) || host->port) &&
23304                                             !buffer_is_empty(host->unixsocket)) {
23305 -                                               log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
23306 +                                               log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23307                                                                 "either host/port or socket have to be set in:",
23308 -                                                               da->key, "= (", 
23309 +                                                               da->key, "= (",
23310                                                                 da_ext->key, " => (",
23311                                                                 da_host->key, " ( ...");
23312  
23313                                                 return HANDLER_ERROR;
23314                                         }
23315 -                                       
23316 +
23317                                         if (!buffer_is_empty(host->unixsocket)) {
23318                                                 /* unix domain socket */
23319 -                                               
23320 +
23321                                                 if (host->unixsocket->used > UNIX_PATH_MAX - 2) {
23322 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
23323 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23324                                                                         "unixsocket is too long in:",
23325 -                                                                       da->key, "= (", 
23326 +                                                                       da->key, "= (",
23327                                                                         da_ext->key, " => (",
23328                                                                         da_host->key, " ( ...");
23329  
23330 @@ -1288,37 +1243,37 @@
23331                                                 }
23332                                         } else {
23333                                                 /* tcp/ip */
23334 -                                               
23335 -                                               if (buffer_is_empty(host->host) && 
23336 +
23337 +                                               if (buffer_is_empty(host->host) &&
23338                                                     buffer_is_empty(host->bin_path)) {
23339 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
23340 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23341                                                                         "host or binpath have to be set in:",
23342 -                                                                       da->key, "= (", 
23343 +                                                                       da->key, "= (",
23344                                                                         da_ext->key, " => (",
23345                                                                         da_host->key, " ( ...");
23346 -                                                       
23347 +
23348                                                         return HANDLER_ERROR;
23349                                                 } else if (host->port == 0) {
23350 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
23351 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23352                                                                         "port has to be set in:",
23353 -                                                                       da->key, "= (", 
23354 +                                                                       da->key, "= (",
23355                                                                         da_ext->key, " => (",
23356                                                                         da_host->key, " ( ...");
23357  
23358                                                         return HANDLER_ERROR;
23359                                                 }
23360                                         }
23361 -                                               
23362 -                                       if (!buffer_is_empty(host->bin_path)) { 
23363 +
23364 +                                       if (!buffer_is_empty(host->bin_path)) {
23365                                                 /* a local socket + self spawning */
23366                                                 size_t pno;
23367  
23368                                                 /* HACK:  just to make sure the adaptive spawing is disabled */
23369                                                 host->min_procs = host->max_procs;
23370 -                                               
23371 +
23372                                                 if (host->min_procs > host->max_procs) host->max_procs = host->min_procs;
23373                                                 if (host->max_load_per_proc < 1) host->max_load_per_proc = 0;
23374 -                                               
23375 +
23376                                                 if (s->debug) {
23377                                                         log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
23378                                                                         "--- fastcgi spawning local",
23379 @@ -1328,7 +1283,7 @@
23380                                                                         "\n\tmin-procs:", host->min_procs,
23381                                                                         "\n\tmax-procs:", host->max_procs);
23382                                                 }
23383 -                                               
23384 +
23385                                                 for (pno = 0; pno < host->min_procs; pno++) {
23386                                                         fcgi_proc *proc;
23387  
23388 @@ -1343,7 +1298,7 @@
23389                                                                 buffer_append_string(proc->unixsocket, "-");
23390                                                                 buffer_append_long(proc->unixsocket, pno);
23391                                                         }
23392 -                                                       
23393 +
23394                                                         if (s->debug) {
23395                                                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
23396                                                                                 "--- fastcgi spawning",
23397 @@ -1351,7 +1306,7 @@
23398                                                                                 "\n\tsocket", host->unixsocket,
23399                                                                                 "\n\tcurrent:", pno, "/", host->min_procs);
23400                                                         }
23401 -                                                       
23402 +
23403                                                         if (fcgi_spawn_connection(srv, p, host, proc)) {
23404                                                                 log_error_write(srv, __FILE__, __LINE__, "s",
23405                                                                                 "[ERROR]: spawning fcgi failed.");
23406 @@ -1359,35 +1314,35 @@
23407                                                         }
23408  
23409                                                         fastcgi_status_init(srv, p->statuskey, host, proc);
23410 -                                                       
23411 +
23412                                                         proc->next = host->first;
23413                                                         if (host->first)        host->first->prev = proc;
23414 -                                                       
23415 +
23416                                                         host->first = proc;
23417                                                 }
23418                                         } else {
23419                                                 fcgi_proc *proc;
23420 -                                               
23421 +
23422                                                 proc = fastcgi_process_init();
23423                                                 proc->id = host->num_procs++;
23424                                                 host->max_id++;
23425                                                 host->active_procs++;
23426                                                 proc->state = PROC_STATE_RUNNING;
23427 -                                               
23428 +
23429                                                 if (buffer_is_empty(host->unixsocket)) {
23430                                                         proc->port = host->port;
23431                                                 } else {
23432                                                         buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
23433                                                 }
23434 -                                               
23435 +
23436                                                 fastcgi_status_init(srv, p->statuskey, host, proc);
23437  
23438                                                 host->first = proc;
23439 -                                               
23440 +
23441                                                 host->min_procs = 1;
23442                                                 host->max_procs = 1;
23443                                         }
23444 -                                       
23445 +
23446                                         if (!buffer_is_empty(fcgi_mode)) {
23447                                                 if (strcmp(fcgi_mode->ptr, "responder") == 0) {
23448                                                         host->mode = FCGI_RESPONDER;
23449 @@ -1411,16 +1366,16 @@
23450                         }
23451                 }
23452         }
23453 -       
23454 +
23455         buffer_free(fcgi_mode);
23456 -       
23457 +
23458         return HANDLER_GO_ON;
23459  }
23460  
23461  static int fcgi_set_state(server *srv, handler_ctx *hctx, fcgi_connection_state_t state) {
23462         hctx->state = state;
23463         hctx->state_timestamp = srv->cur_ts;
23464 -       
23465 +
23466         return 0;
23467  }
23468  
23469 @@ -1429,13 +1384,13 @@
23470         size_t m = 0;
23471         size_t i;
23472         buffer_uint *r = &(p->fcgi_request_id);
23473 -       
23474 +
23475         UNUSED(srv);
23476  
23477         for (i = 0; i < r->used; i++) {
23478                 if (r->ptr[i] > m) m = r->ptr[i];
23479         }
23480 -       
23481 +
23482         if (r->size == 0) {
23483                 r->size = 16;
23484                 r->ptr = malloc(sizeof(*r->ptr) * r->size);
23485 @@ -1443,54 +1398,55 @@
23486                 r->size += 16;
23487                 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
23488         }
23489 -       
23490 +
23491         r->ptr[r->used++] = ++m;
23492 -       
23493 +
23494         return m;
23495  }
23496  
23497  static int fcgi_requestid_del(server *srv, plugin_data *p, size_t request_id) {
23498         size_t i;
23499         buffer_uint *r = &(p->fcgi_request_id);
23500 -       
23501 +
23502         UNUSED(srv);
23503  
23504         for (i = 0; i < r->used; i++) {
23505                 if (r->ptr[i] == request_id) break;
23506         }
23507 -       
23508 +
23509         if (i != r->used) {
23510                 /* found */
23511 -               
23512 +
23513                 if (i != r->used - 1) {
23514                         r->ptr[i] = r->ptr[r->used - 1];
23515                 }
23516                 r->used--;
23517         }
23518 -       
23519 +
23520         return 0;
23521  }
23522  void fcgi_connection_close(server *srv, handler_ctx *hctx) {
23523         plugin_data *p;
23524         connection  *con;
23525 -       
23526 +
23527         if (NULL == hctx) return;
23528 -       
23529 +
23530         p    = hctx->plugin_data;
23531         con  = hctx->remote_conn;
23532 -       
23533 +
23534         if (con->mode != p->id) {
23535 -               WP();
23536                 return;
23537         }
23538 -       
23539 -       if (hctx->fd != -1) {
23540 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
23541 -               fdevent_unregister(srv->ev, hctx->fd);
23542 -               close(hctx->fd);
23543 +
23544 +       if (hctx->sock->fd != -1) {
23545 +               fdevent_event_del(srv->ev, hctx->sock);
23546 +               fdevent_unregister(srv->ev, hctx->sock);
23547 +               closesocket(hctx->sock->fd);
23548 +               hctx->sock->fd = -1;
23549 +
23550                 srv->cur_fds--;
23551         }
23552 -       
23553 +
23554         if (hctx->request_id != 0) {
23555                 fcgi_requestid_del(srv, p, hctx->request_id);
23556         }
23557 @@ -1499,111 +1455,111 @@
23558                 if (hctx->got_proc) {
23559                         /* after the connect the process gets a load */
23560                         hctx->proc->load--;
23561 -                       
23562 -                       status_counter_dec(srv, CONST_STR_LEN("fastcgi.active-requests"));
23563 +
23564 +                       status_counter_dec(CONST_STR_LEN("fastcgi.active-requests"));
23565  
23566                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
23567                         buffer_append_string(p->statuskey, ".load");
23568  
23569 -                       status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
23570 +                       status_counter_set(CONST_BUF_LEN(p->statuskey), hctx->proc->load);
23571  
23572                         if (p->conf.debug) {
23573                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
23574 -                                               "released proc:", 
23575 -                                               "pid:", hctx->proc->pid, 
23576 -                                               "socket:", hctx->proc->connection_name, 
23577 +                                               "released proc:",
23578 +                                               "pid:", hctx->proc->pid,
23579 +                                               "socket:", hctx->proc->connection_name,
23580                                                 "load:", hctx->proc->load);
23581                         }
23582                 }
23583         }
23584  
23585 -       
23586 +
23587         handler_ctx_free(hctx);
23588 -       con->plugin_ctx[p->id] = NULL;  
23589 +       con->plugin_ctx[p->id] = NULL;
23590  }
23591  
23592  static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
23593         plugin_data *p    = hctx->plugin_data;
23594 -       
23595 -       /* child died 
23596 -        * 
23597 -        * 1. 
23598 -        * 
23599 +
23600 +       /* child died
23601 +        *
23602 +        * 1.
23603 +        *
23604          * connect was ok, connection was accepted
23605          * but the php accept loop checks after the accept if it should die or not.
23606 -        * 
23607 -        * if yes we can only detect it at a write() 
23608 -        * 
23609 +        *
23610 +        * if yes we can only detect it at a write()
23611 +        *
23612          * next step is resetting this attemp and setup a connection again
23613 -        * 
23614 +        *
23615          * if we have more then 5 reconnects for the same request, die
23616 -        * 
23617 -        * 2. 
23618 -        * 
23619 +        *
23620 +        * 2.
23621 +        *
23622          * we have a connection but the child died by some other reason
23623 -        * 
23624 +        *
23625          */
23626  
23627 -       if (hctx->fd != -1) {
23628 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
23629 -               fdevent_unregister(srv->ev, hctx->fd);
23630 -               close(hctx->fd);
23631 +       if (hctx->sock->fd != -1) {
23632 +               fdevent_event_del(srv->ev, hctx->sock);
23633 +               fdevent_unregister(srv->ev, hctx->sock);
23634 +               close(hctx->sock->fd);
23635                 srv->cur_fds--;
23636 -               hctx->fd = -1;
23637 +               hctx->sock->fd = -1;
23638         }
23639 -       
23640 +
23641         fcgi_requestid_del(srv, p, hctx->request_id);
23642 -       
23643 +
23644         fcgi_set_state(srv, hctx, FCGI_STATE_INIT);
23645 -       
23646 +
23647         hctx->request_id = 0;
23648         hctx->reconnects++;
23649 -       
23650 +
23651         if (p->conf.debug > 2) {
23652                 if (hctx->proc) {
23653                         log_error_write(srv, __FILE__, __LINE__, "sdb",
23654 -                                       "release proc for reconnect:", 
23655 +                                       "release proc for reconnect:",
23656                                         hctx->proc->pid, hctx->proc->connection_name);
23657                 } else {
23658                         log_error_write(srv, __FILE__, __LINE__, "sb",
23659 -                                       "release proc for reconnect:", 
23660 +                                       "release proc for reconnect:",
23661                                         hctx->host->unixsocket);
23662                 }
23663         }
23664  
23665 -       if (hctx->proc && hctx->got_proc) {     
23666 +       if (hctx->proc && hctx->got_proc) {
23667                 hctx->proc->load--;
23668         }
23669  
23670         /* perhaps another host gives us more luck */
23671         hctx->host->load--;
23672         hctx->host = NULL;
23673 -       
23674 +
23675         return 0;
23676  }
23677  
23678  
23679  static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) {
23680         plugin_data *p = p_d;
23681 -       
23682 +
23683         fcgi_connection_close(srv, con->plugin_ctx[p->id]);
23684 -       
23685 +
23686         return HANDLER_GO_ON;
23687  }
23688  
23689  
23690  static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
23691         size_t len;
23692 -       
23693 +
23694         if (!key || !val) return -1;
23695 -       
23696 +
23697         len = key_len + val_len;
23698 -       
23699 +
23700         len += key_len > 127 ? 4 : 1;
23701         len += val_len > 127 ? 4 : 1;
23702 -       
23703 +
23704         buffer_prepare_append(env, len);
23705 -       
23706 +
23707         if (key_len > 127) {
23708                 env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80;
23709                 env->ptr[env->used++] = (key_len >> 16) & 0xff;
23710 @@ -1612,7 +1568,7 @@
23711         } else {
23712                 env->ptr[env->used++] = (key_len >> 0) & 0xff;
23713         }
23714 -       
23715 +
23716         if (val_len > 127) {
23717                 env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80;
23718                 env->ptr[env->used++] = (val_len >> 16) & 0xff;
23719 @@ -1621,12 +1577,12 @@
23720         } else {
23721                 env->ptr[env->used++] = (val_len >> 0) & 0xff;
23722         }
23723 -       
23724 +
23725         memcpy(env->ptr + env->used, key, key_len);
23726         env->used += key_len;
23727         memcpy(env->ptr + env->used, val, val_len);
23728         env->used += val_len;
23729 -       
23730 +
23731         return 0;
23732  }
23733  
23734 @@ -1639,11 +1595,11 @@
23735         header->contentLengthB1 = (contentLength >> 8) & 0xff;
23736         header->paddingLength = paddingLength;
23737         header->reserved = 0;
23738 -       
23739 +
23740         return 0;
23741  }
23742  /**
23743 - * 
23744 + *
23745   * returns
23746   *   -1 error
23747   *    0 connected
23748 @@ -1665,26 +1621,23 @@
23749         struct sockaddr_un fcgi_addr_un;
23750  #endif
23751         socklen_t servlen;
23752 -       
23753 +
23754         fcgi_extension_host *host = hctx->host;
23755         fcgi_proc *proc   = hctx->proc;
23756 -       int fcgi_fd       = hctx->fd;
23757 -       
23758 +       int fcgi_fd       = hctx->sock->fd;
23759 +
23760         memset(&fcgi_addr, 0, sizeof(fcgi_addr));
23761 -       
23762 +
23763         if (!buffer_is_empty(proc->unixsocket)) {
23764  #ifdef HAVE_SYS_UN_H
23765                 /* use the unix domain socket */
23766                 fcgi_addr_un.sun_family = AF_UNIX;
23767                 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
23768 -#ifdef SUN_LEN
23769 +
23770                 servlen = SUN_LEN(&fcgi_addr_un);
23771 -#else
23772 -               /* stevens says: */
23773 -               servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
23774 -#endif
23775 +
23776                 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
23777 -       
23778 +
23779                 if (buffer_is_empty(proc->connection_name)) {
23780                         /* on remote spawing we have to set the connection-name now */
23781                         buffer_copy_string(proc->connection_name, "unix:");
23782 @@ -1695,16 +1648,18 @@
23783  #endif
23784         } else {
23785                 fcgi_addr_in.sin_family = AF_INET;
23786 +
23787                 if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) {
23788 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
23789 -                                       "converting IP-adress failed for", host->host, 
23790 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
23791 +                                       "converting IP-adress failed for", host->host,
23792                                         "\nBe sure to specify an IP address here");
23793 -                       
23794 +
23795                         return -1;
23796                 }
23797 +
23798                 fcgi_addr_in.sin_port = htons(proc->port);
23799                 servlen = sizeof(fcgi_addr_in);
23800 -               
23801 +
23802                 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
23803  
23804                 if (buffer_is_empty(proc->connection_name)) {
23805 @@ -1715,20 +1670,20 @@
23806                         buffer_append_long(proc->connection_name, proc->port);
23807                 }
23808         }
23809 -       
23810 +
23811         if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
23812 -               if (errno == EINPROGRESS || 
23813 +               if (errno == EINPROGRESS ||
23814                     errno == EALREADY ||
23815                     errno == EINTR) {
23816                         if (hctx->conf.debug > 2) {
23817 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
23818 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
23819                                         "connect delayed, will continue later:", proc->connection_name);
23820                         }
23821 -                       
23822 +
23823                         return CONNECTION_DELAYED;
23824                 } else if (errno == EAGAIN) {
23825                         if (hctx->conf.debug) {
23826 -                               log_error_write(srv, __FILE__, __LINE__, "sbsd", 
23827 +                               log_error_write(srv, __FILE__, __LINE__, "sbsd",
23828                                         "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
23829                                         "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
23830                                         "The load for this fastcgi backend", proc->connection_name, "is", proc->load);
23831 @@ -1736,8 +1691,8 @@
23832  
23833                         return CONNECTION_OVERLOADED;
23834                 } else {
23835 -                       log_error_write(srv, __FILE__, __LINE__, "sssb", 
23836 -                                       "connect failed:", 
23837 +                       log_error_write(srv, __FILE__, __LINE__, "sssb",
23838 +                                       "connect failed:",
23839                                         strerror(errno), "on",
23840                                         proc->connection_name);
23841  
23842 @@ -1747,7 +1702,7 @@
23843  
23844         hctx->reconnects = 0;
23845         if (hctx->conf.debug > 1) {
23846 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
23847 +               log_error_write(srv, __FILE__, __LINE__, "sd",
23848                                 "connect succeeded: ", fcgi_fd);
23849         }
23850  
23851 @@ -1756,21 +1711,21 @@
23852  
23853  static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
23854         size_t i;
23855 -       
23856 +
23857         for (i = 0; i < con->request.headers->used; i++) {
23858                 data_string *ds;
23859 -               
23860 +
23861                 ds = (data_string *)con->request.headers->data[i];
23862 -               
23863 +
23864                 if (ds->value->used && ds->key->used) {
23865                         size_t j;
23866                         buffer_reset(srv->tmp_buf);
23867 -                       
23868 +
23869                         if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
23870                                 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
23871                                 srv->tmp_buf->used--;
23872                         }
23873 -                       
23874 +
23875                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
23876                         for (j = 0; j < ds->key->used - 1; j++) {
23877                                 char c = '_';
23878 @@ -1784,20 +1739,20 @@
23879                                 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
23880                         }
23881                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
23882 -                       
23883 +
23884                         fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
23885                 }
23886         }
23887 -       
23888 +
23889         for (i = 0; i < con->environment->used; i++) {
23890                 data_string *ds;
23891 -               
23892 +
23893                 ds = (data_string *)con->environment->data[i];
23894 -               
23895 +
23896                 if (ds->value->used && ds->key->used) {
23897                         size_t j;
23898                         buffer_reset(srv->tmp_buf);
23899 -                       
23900 +
23901                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
23902                         for (j = 0; j < ds->key->used - 1; j++) {
23903                                 char c = '_';
23904 @@ -1811,11 +1766,11 @@
23905                                 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
23906                         }
23907                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
23908 -                       
23909 +
23910                         fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
23911                 }
23912         }
23913 -       
23914 +
23915         return 0;
23916  }
23917  
23918 @@ -1824,24 +1779,24 @@
23919         FCGI_BeginRequestRecord beginRecord;
23920         FCGI_Header header;
23921         buffer *b;
23922 -       
23923 +
23924         char buf[32];
23925         const char *s;
23926  #ifdef HAVE_IPV6
23927         char b2[INET6_ADDRSTRLEN + 1];
23928  #endif
23929 -       
23930 +
23931         plugin_data *p    = hctx->plugin_data;
23932         fcgi_extension_host *host= hctx->host;
23933  
23934         connection *con   = hctx->remote_conn;
23935         server_socket *srv_sock = con->srv_socket;
23936 -       
23937 +
23938         sock_addr our_addr;
23939         socklen_t our_addr_len;
23940 -       
23941 +
23942         /* send FCGI_BEGIN_REQUEST */
23943 -       
23944 +
23945         fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, request_id, sizeof(beginRecord.body), 0);
23946         beginRecord.body.roleB0 = host->mode;
23947         beginRecord.body.roleB1 = 0;
23948 @@ -1849,21 +1804,21 @@
23949         memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
23950  
23951         b = chunkqueue_get_append_buffer(hctx->wb);
23952 -       
23953 +
23954         buffer_copy_memory(b, (const char *)&beginRecord, sizeof(beginRecord));
23955 -       
23956 +
23957         /* send FCGI_PARAMS */
23958         buffer_prepare_copy(p->fcgi_env, 1024);
23959  
23960  
23961         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
23962 -       
23963 +
23964         if (con->server_name->used) {
23965                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
23966         } else {
23967  #ifdef HAVE_IPV6
23968 -               s = inet_ntop(srv_sock->addr.plain.sa_family, 
23969 -                             srv_sock->addr.plain.sa_family == AF_INET6 ? 
23970 +               s = inet_ntop(srv_sock->addr.plain.sa_family,
23971 +                             srv_sock->addr.plain.sa_family == AF_INET6 ?
23972                               (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
23973                               (const void *) &(srv_sock->addr.ipv4.sin_addr),
23974                               b2, sizeof(b2)-1);
23975 @@ -1872,50 +1827,50 @@
23976  #endif
23977                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
23978         }
23979 -       
23980 +
23981         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
23982 -       
23983 -       ltostr(buf, 
23984 +
23985 +       ltostr(buf,
23986  #ifdef HAVE_IPV6
23987                ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
23988  #else
23989                ntohs(srv_sock->addr.ipv4.sin_port)
23990  #endif
23991                );
23992 -       
23993 +
23994         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
23995 -       
23996 +
23997         /* get the server-side of the connection to the client */
23998         our_addr_len = sizeof(our_addr);
23999 -       
24000 -       if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
24001 +
24002 +       if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
24003                 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
24004         } else {
24005                 s = inet_ntop_cache_get_ip(srv, &(our_addr));
24006         }
24007         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
24008 -       
24009 -       ltostr(buf, 
24010 +
24011 +       ltostr(buf,
24012  #ifdef HAVE_IPV6
24013                ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
24014  #else
24015                ntohs(con->dst_addr.ipv4.sin_port)
24016  #endif
24017                );
24018 -       
24019 +
24020         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
24021 -       
24022 +
24023         s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
24024         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
24025 -       
24026 +
24027         if (!buffer_is_empty(con->authed_user)) {
24028                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_USER"),
24029                              CONST_BUF_LEN(con->authed_user));
24030         }
24031 -       
24032 +
24033         if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) {
24034                 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
24035 -               
24036 +
24037                 /* request.content_length < SSIZE_MAX, see request.c */
24038                 ltostr(buf, con->request.content_length);
24039                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
24040 @@ -1930,12 +1885,12 @@
24041                  */
24042  
24043                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
24044 -               
24045 +
24046                 if (!buffer_is_empty(con->request.pathinfo)) {
24047                         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
24048 -                       
24049 +
24050                         /* PATH_TRANSLATED is only defined if PATH_INFO is set */
24051 -                       
24052 +
24053                         if (!buffer_is_empty(host->docroot)) {
24054                                 buffer_copy_string_buffer(p->path, host->docroot);
24055                         } else {
24056 @@ -1957,27 +1912,27 @@
24057          */
24058  
24059         if (!buffer_is_empty(host->docroot)) {
24060 -               /* 
24061 -                * rewrite SCRIPT_FILENAME 
24062 -                * 
24063 +               /*
24064 +                * rewrite SCRIPT_FILENAME
24065 +                *
24066                  */
24067 -               
24068 +
24069                 buffer_copy_string_buffer(p->path, host->docroot);
24070                 buffer_append_string_buffer(p->path, con->uri.path);
24071 -               
24072 +
24073                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
24074                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
24075         } else {
24076                 buffer_copy_string_buffer(p->path, con->physical.path);
24077 -               
24078 -               /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself 
24079 -                * 
24080 +
24081 +               /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
24082 +                *
24083                  * see src/sapi/cgi_main.c, init_request_info()
24084                  */
24085                 if (host->break_scriptfilename_for_php) {
24086                         buffer_append_string_buffer(p->path, con->request.pathinfo);
24087                 }
24088 -               
24089 +
24090                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
24091                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
24092         }
24093 @@ -1987,7 +1942,7 @@
24094                 /**
24095                  * /app1/index/list
24096                  *
24097 -                * stripping /app1 or /app1/ should lead to 
24098 +                * stripping /app1 or /app1/ should lead to
24099                  *
24100                  * /index/list
24101                  *
24102 @@ -2001,7 +1956,7 @@
24103                     0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, host->strip_request_uri->used - 1)) {
24104                         /* the left is the same */
24105  
24106 -                       fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), 
24107 +                       fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
24108                                         con->request.orig_uri->ptr + (host->strip_request_uri->used - 2),
24109                                         con->request.orig_uri->used - (host->strip_request_uri->used - 2));
24110                 } else {
24111 @@ -2018,26 +1973,26 @@
24112         } else {
24113                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
24114         }
24115 -       
24116 +
24117         s = get_http_method_name(con->request.http_method);
24118         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
24119         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
24120         s = get_http_version_name(con->request.http_version);
24121         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
24122 -       
24123 +
24124  #ifdef USE_OPENSSL
24125         if (srv_sock->is_ssl) {
24126                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
24127         }
24128  #endif
24129 -       
24130 -       
24131 +
24132 +
24133         fcgi_env_add_request_headers(srv, con, p);
24134 -       
24135 +
24136         fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0);
24137         buffer_append_memory(b, (const char *)&header, sizeof(header));
24138         buffer_append_memory(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used);
24139 -       
24140 +
24141         fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
24142         buffer_append_memory(b, (const char *)&header, sizeof(header));
24143  
24144 @@ -2057,7 +2012,7 @@
24145  
24146                         /* we announce toWrite octects
24147                          * now take all the request_content chunk that we need to fill this request
24148 -                        * */   
24149 +                        * */
24150  
24151                         b = chunkqueue_get_append_buffer(hctx->wb);
24152                         fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0);
24153 @@ -2080,16 +2035,16 @@
24154                                         if (weHave > weWant - written) weHave = weWant - written;
24155  
24156                                         if (p->conf.debug > 10) {
24157 -                                               fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n", 
24158 -                                                               __FILE__, __LINE__, 
24159 -                                                               weHave, 
24160 -                                                               req_c->offset, 
24161 -                                                               req_c->file.length, 
24162 +                                               fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n",
24163 +                                                               __FILE__, __LINE__,
24164 +                                                               weHave,
24165 +                                                               req_c->offset,
24166 +                                                               req_c->file.length,
24167                                                                 req_c->file.name->ptr);
24168                                         }
24169  
24170                                         assert(weHave != 0);
24171 -                                       
24172 +
24173                                         chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
24174  
24175                                         req_c->offset += weHave;
24176 @@ -2104,7 +2059,7 @@
24177                                          * - we reference the tempfile from the request-content-queue several times
24178                                          *   if the req_c is larger than FCGI_MAX_LENGTH
24179                                          * - we can't simply cleanup the request-content-queue as soon as possible
24180 -                                        *   as it would remove the tempfiles 
24181 +                                        *   as it would remove the tempfiles
24182                                          * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last
24183                                          *   referencing chunk of the fastcgi-write-queue
24184                                          *
24185 @@ -2141,7 +2096,7 @@
24186                                         req_c->offset += weHave;
24187                                         req_cq->bytes_out += weHave;
24188                                         written += weHave;
24189 -                                       
24190 +
24191                                         hctx->wb->bytes_in += weHave;
24192  
24193                                         if (req_c->offset == req_c->mem->used - 1) {
24194 @@ -2155,12 +2110,12 @@
24195                                         break;
24196                                 }
24197                         }
24198 -                       
24199 +
24200                         b->used++; /* add virtual \0 */
24201                         offset += weWant;
24202                 }
24203         }
24204 -       
24205 +
24206         b = chunkqueue_get_append_buffer(hctx->wb);
24207         /* terminate STDIN */
24208         fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0);
24209 @@ -2175,118 +2130,19 @@
24210                 if ((i+1) % 16 == 0) {
24211                         size_t j;
24212                         for (j = i-15; j <= i; j++) {
24213 -                               fprintf(stderr, "%c", 
24214 +                               fprintf(stderr, "%c",
24215                                         isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
24216                         }
24217                         fprintf(stderr, "\n");
24218                 }
24219         }
24220  #endif
24221 -       
24222 -       return 0;
24223 -}
24224  
24225 -static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
24226 -       char *s, *ns;
24227 -       
24228 -       handler_ctx *hctx = con->plugin_ctx[p->id];
24229 -       fcgi_extension_host *host= hctx->host;
24230 -       
24231 -       UNUSED(srv);
24232 -
24233 -       buffer_copy_string_buffer(p->parse_response, in);
24234 -       
24235 -       /* search for \n */
24236 -       for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {
24237 -               char *key, *value;
24238 -               int key_len;
24239 -               data_string *ds;
24240 -               
24241 -               /* a good day. Someone has read the specs and is sending a \r\n to us */
24242 -               
24243 -               if (ns > p->parse_response->ptr &&
24244 -                   *(ns-1) == '\r') {
24245 -                       *(ns-1) = '\0';
24246 -               }
24247 -               
24248 -               ns[0] = '\0';
24249 -               
24250 -               key = s;
24251 -               if (NULL == (value = strchr(s, ':'))) {
24252 -                       /* we expect: "<key>: <value>\n" */
24253 -                       continue;
24254 -               }
24255 -               
24256 -               key_len = value - key;
24257 -               
24258 -               value++;
24259 -               /* strip WS */
24260 -               while (*value == ' ' || *value == '\t') value++;
24261 -               
24262 -               if (host->mode != FCGI_AUTHORIZER ||
24263 -                   !(con->http_status == 0 ||
24264 -                     con->http_status == 200)) {
24265 -                       /* authorizers shouldn't affect the response headers sent back to the client */
24266 -                       
24267 -                       /* don't forward Status: */
24268 -                       if (0 != strncasecmp(key, "Status", key_len)) {
24269 -                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
24270 -                                       ds = data_response_init();
24271 -                               }
24272 -                               buffer_copy_string_len(ds->key, key, key_len);
24273 -                               buffer_copy_string(ds->value, value);
24274 -                               
24275 -                               array_insert_unique(con->response.headers, (data_unset *)ds);
24276 -                       }
24277 -               }
24278 -               
24279 -               switch(key_len) {
24280 -               case 4:
24281 -                       if (0 == strncasecmp(key, "Date", key_len)) {
24282 -                               con->parsed_response |= HTTP_DATE;
24283 -                       }
24284 -                       break;
24285 -               case 6:
24286 -                       if (0 == strncasecmp(key, "Status", key_len)) {
24287 -                               con->http_status = strtol(value, NULL, 10);
24288 -                               con->parsed_response |= HTTP_STATUS;
24289 -                       }
24290 -                       break;
24291 -               case 8:
24292 -                       if (0 == strncasecmp(key, "Location", key_len)) {
24293 -                               con->parsed_response |= HTTP_LOCATION;
24294 -                       }
24295 -                       break;
24296 -               case 10:
24297 -                       if (0 == strncasecmp(key, "Connection", key_len)) {
24298 -                               con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
24299 -                               con->parsed_response |= HTTP_CONNECTION;
24300 -                       }
24301 -                       break;
24302 -               case 14:
24303 -                       if (0 == strncasecmp(key, "Content-Length", key_len)) {
24304 -                               con->response.content_length = strtol(value, NULL, 10);
24305 -                               con->parsed_response |= HTTP_CONTENT_LENGTH;
24306 -                               
24307 -                               if (con->response.content_length < 0) con->response.content_length = 0;
24308 -                       }
24309 -                       break;
24310 -               default:
24311 -                       break;
24312 -               }
24313 -       }
24314 -       
24315 -       /* CGI/1.1 rev 03 - 7.2.1.2 */
24316 -       if ((con->parsed_response & HTTP_LOCATION) &&
24317 -           !(con->parsed_response & HTTP_STATUS)) {
24318 -               con->http_status = 302;
24319 -       }
24320 -       
24321         return 0;
24322  }
24323  
24324  typedef struct {
24325 -       buffer  *b; 
24326 +       buffer  *b;
24327         size_t   len;
24328         int      type;
24329         int      padding;
24330 @@ -2327,9 +2183,9 @@
24331                 return -1;
24332         }
24333  
24334 -       /* we have at least a header, now check how much me have to fetch */ 
24335 +       /* we have at least a header, now check how much me have to fetch */
24336         header = (FCGI_Header *)(packet->b->ptr);
24337 -                       
24338 +
24339         packet->len = (header->contentLengthB0 | (header->contentLengthB1 << 8)) + header->paddingLength;
24340         packet->request_id = (header->requestIdB0 | (header->requestIdB1 << 8));
24341         packet->type = header->type;
24342 @@ -2348,7 +2204,7 @@
24343                         size_t weHave = c->mem->used - c->offset - offset - 1;
24344  
24345                         if (weHave > weWant) weHave = weWant;
24346 -                                               
24347 +
24348                         buffer_append_string_len(packet->b, c->mem->ptr + c->offset + offset, weHave);
24349  
24350                         /* we only skipped the first 8 bytes as they are the fcgi header */
24351 @@ -2380,65 +2236,42 @@
24352         }
24353  
24354         chunkqueue_remove_finished_chunks(hctx->rb);
24355 -       
24356 +
24357         return 0;
24358  }
24359  
24360  static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
24361         int fin = 0;
24362 -       int toread;
24363 -       ssize_t r;
24364 -       
24365 +
24366         plugin_data *p    = hctx->plugin_data;
24367         connection *con   = hctx->remote_conn;
24368 -       int fcgi_fd       = hctx->fd;
24369         fcgi_extension_host *host= hctx->host;
24370         fcgi_proc *proc   = hctx->proc;
24371 -       
24372 -       /* 
24373 -        * check how much we have to read 
24374 -        */
24375 -       if (ioctl(hctx->fd, FIONREAD, &toread)) {
24376 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
24377 -                               "unexpected end-of-file (perhaps the fastcgi process died):",
24378 -                               fcgi_fd);
24379 -               return -1;
24380 -       }
24381 -       
24382 -       /* init read-buffer */
24383 -       
24384 -       if (toread > 0) {
24385 -               buffer *b;
24386 -
24387 -               b = chunkqueue_get_append_buffer(hctx->rb);
24388 -               buffer_prepare_copy(b, toread + 1);
24389 -
24390 -               /* append to read-buffer */
24391 -               if (-1 == (r = read(hctx->fd, b->ptr, toread))) {
24392 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
24393 -                                       "unexpected end-of-file (perhaps the fastcgi process died):",
24394 -                                       fcgi_fd, strerror(errno));
24395 -                       return -1;
24396 -               }
24397 -               
24398 -               /* this should be catched by the b > 0 above */
24399 -               assert(r);
24400 +       handler_t ret;
24401  
24402 -               b->used = r + 1; /* one extra for the fake \0 */
24403 -               b->ptr[b->used - 1] = '\0';
24404 -       } else {
24405 -               log_error_write(srv, __FILE__, __LINE__, "ssdsb", 
24406 -                               "unexpected end-of-file (perhaps the fastcgi process died):",
24407 -                               "pid:", proc->pid,
24408 -                               "socket:", proc->connection_name);
24409 -               
24410 +       /* in case we read nothing, check the return code
24411 +        * if we got something, be happy :)
24412 +        *
24413 +        * Ok, to be honest:
24414 +        * - it is fine to receive a EAGAIN on a second read() call
24415 +        * - it might be fine they we get a con-close on a second read() call */
24416 +       switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
24417 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
24418 +               /* a EAGAIN after we read exactly the chunk-size */
24419 +
24420 +               ERROR("%s", "oops, got a EAGAIN even if we just got call for the event, wired");
24421 +               return -1;
24422 +       case NETWORK_STATUS_SUCCESS:
24423 +               break;
24424 +       default:
24425 +               ERROR("reading from fastcgi socket failed (fd=%d)", hctx->sock->fd);
24426                 return -1;
24427         }
24428  
24429         /*
24430          * parse the fastcgi packets and forward the content to the write-queue
24431          *
24432 -        */     
24433 +        */
24434         while (fin == 0) {
24435                 fastcgi_response_packet packet;
24436  
24437 @@ -2454,92 +2287,136 @@
24438  
24439                         /* is the header already finished */
24440                         if (0 == con->file_started) {
24441 -                               char *c;
24442 -                               size_t blen;
24443 -                               data_string *ds;
24444 -                                       
24445 -                               /* search for header terminator 
24446 -                                * 
24447 -                                * if we start with \r\n check if last packet terminated with \r\n
24448 -                                * if we start with \n check if last packet terminated with \n
24449 -                                * search for \r\n\r\n
24450 -                                * search for \n\n
24451 -                                */
24452 -
24453 -                               if (hctx->response_header->used == 0) {
24454 -                                       buffer_copy_string_buffer(hctx->response_header, packet.b);
24455 -                               } else {
24456 -                                       buffer_append_string_buffer(hctx->response_header, packet.b);
24457 -                               }
24458 -
24459 -                               if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) {
24460 -                                       blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 4;
24461 -                                       hctx->response_header->used = (c - hctx->response_header->ptr) + 3;
24462 -                                       c += 4; /* point the the start of the response */
24463 -                               } else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) {
24464 -                                       blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 2;
24465 -                                       hctx->response_header->used = c - hctx->response_header->ptr + 2;
24466 -                                       c += 2; /* point the the start of the response */
24467 -                               } else {
24468 -                                       /* no luck, no header found */
24469 +                               int have_content_length = 0;
24470 +                               int need_more = 0;
24471 +                               size_t i;
24472 +
24473 +                               /* append the current packet to the chunk queue */
24474 +                               chunkqueue_append_buffer(hctx->http_rb, packet.b);
24475 +                               http_response_reset(p->resp);
24476 +
24477 +                               switch(http_response_parse_cq(hctx->http_rb, p->resp)) {
24478 +                               case PARSE_ERROR:
24479 +                                       /* parsing the response header failed */
24480 +
24481 +                                       con->http_status = 502; /* Bad Gateway */
24482 +
24483 +                                       return 1;
24484 +                               case PARSE_NEED_MORE:
24485 +                                       need_more = 1;
24486 +                                       break; /* leave the loop */
24487 +                               case PARSE_SUCCESS:
24488                                         break;
24489 +                               default:
24490 +                                       /* should not happen */
24491 +                                       SEGFAULT();
24492                                 }
24493  
24494 -                               /* parse the response header */
24495 -                               fcgi_response_parse(srv, con, p, hctx->response_header);
24496 +                               if (need_more) break;
24497  
24498 -                               con->file_started = 1;
24499 +                               chunkqueue_remove_finished_chunks(hctx->http_rb);
24500 +
24501 +                               con->http_status = p->resp->status;
24502 +                               hctx->send_content_body = 1;
24503  
24504 -                               if (host->mode == FCGI_AUTHORIZER &&
24505 -                                   (con->http_status == 0 ||
24506 -                                    con->http_status == 200)) {
24507 -                                       /* a authorizer with approved the static request, ignore the content here */
24508 -                                       hctx->send_content_body = 0;
24509 -                               }
24510 -
24511 -                               if (host->allow_xsendfile &&
24512 -                                   NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))) {
24513 -                                       stat_cache_entry *sce;
24514 -
24515 -                                       if (HANDLER_ERROR != stat_cache_get_entry(srv, con, ds->value, &sce)) {
24516 -                                               /* found */
24517 -
24518 -                                               http_chunk_append_file(srv, con, ds->value, 0, sce->st.st_size);
24519 -                                               hctx->send_content_body = 0; /* ignore the content */
24520 -                                               joblist_append(srv, con);
24521 +                               /* handle the header fields */
24522 +                               if (host->mode == FCGI_AUTHORIZER) {
24523 +                                       /* auth mode is a bit different */
24524 +
24525 +                                       if (con->http_status == 0 ||
24526 +                                           con->http_status == 200) {
24527 +                                               /* a authorizer with approved the static request, ignore the content here */
24528 +                                               hctx->send_content_body = 0;
24529                                         }
24530                                 }
24531  
24532 +                               /* copy the http-headers */
24533 +                               for (i = 0; i < p->resp->headers->used; i++) {
24534 +                                       const char *ign[] = { "Status", NULL };
24535 +                                       size_t j;
24536 +                                       data_string *ds;
24537 +
24538 +                                       data_string *header = (data_string *)p->resp->headers->data[i];
24539 +
24540 +                                       /* ignore all headers in AUTHORIZER mode */
24541 +                                       if (host->mode == FCGI_AUTHORIZER) continue;
24542 +
24543 +                                       /* some headers are ignored by default */
24544 +                                       for (j = 0; ign[j]; j++) {
24545 +                                               if (0 == strcasecmp(ign[j], header->key->ptr)) break;
24546 +                                       }
24547 +                                       if (ign[j]) continue;
24548 +
24549 +                                       if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
24550 +                                               /* CGI/1.1 rev 03 - 7.2.1.2 */
24551 +                                               con->http_status = 302;
24552 +                                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
24553 +                                               have_content_length = 1;
24554 +                                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Sendfile")) || 
24555 +                                                  0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-LIGHTTPD-send-file"))) {
24556 +                                               
24557 +                                               stat_cache_entry *sce;
24558                                                 
24559 -                               if (hctx->send_content_body && blen > 1) {                                              
24560 -                                       /* enable chunked-transfer-encoding */
24561 +                                               if (host->allow_xsendfile &&
24562 +                                                   HANDLER_ERROR != stat_cache_get_entry(srv, con, header->value, &sce)) {
24563 +                                                       http_chunk_append_file(srv, con, header->value, 0, sce->st.st_size);
24564 +                                                       hctx->send_content_body = 0; /* ignore the content */
24565 +                                       
24566 +                                                       joblist_append(srv, con);
24567 +                                               }
24568 +
24569 +                                               continue; /* ignore header */
24570 +                                       }
24571 +                                       
24572 +                                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
24573 +                                               ds = data_response_init();
24574 +                                       }
24575 +                                       buffer_copy_string_buffer(ds->key, header->key);
24576 +                                       buffer_copy_string_buffer(ds->value, header->value);
24577 +
24578 +                                       array_insert_unique(con->response.headers, (data_unset *)ds);
24579 +                               }
24580 +
24581 +                               /* header is complete ... go on with the body */
24582 +
24583 +                               con->file_started = 1;
24584 +
24585 +                               if (hctx->send_content_body) {
24586 +                                       chunk *c = hctx->http_rb->first;
24587 +
24588 +                                       /* if we don't have a content-length enable chunked encoding 
24589 +                                        * if possible
24590 +                                        * 
24591 +                                        * TODO: move this to a later stage in the filter-queue
24592 +                                        *  */
24593                                         if (con->request.http_version == HTTP_VERSION_1_1 &&
24594 -                                           !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
24595 +                                           !have_content_length) {
24596                                                 con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
24597                                         }
24598  
24599 -                                       http_chunk_append_mem(srv, con, c, blen);
24600 +                                       /* copy the rest of the data */
24601 +                                       for (c = hctx->http_rb->first; c; c = c->next) {
24602 +                                               if (c->mem->used > 1) {
24603 +                                                       http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
24604 +                                                       c->offset = c->mem->used - 1;
24605 +                                               }
24606 +                                       }
24607 +                                       chunkqueue_remove_finished_chunks(hctx->http_rb);
24608                                         joblist_append(srv, con);
24609                                 }
24610                         } else if (hctx->send_content_body && packet.b->used > 1) {
24611 -                               if (con->request.http_version == HTTP_VERSION_1_1 &&
24612 -                                   !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
24613 -                                       /* enable chunked-transfer-encoding */
24614 -                                       con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
24615 -                               }
24616 -
24617                                 http_chunk_append_mem(srv, con, packet.b->ptr, packet.b->used);
24618                                 joblist_append(srv, con);
24619                         }
24620                         break;
24621                 case FCGI_STDERR:
24622 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
24623 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
24624                                         "FastCGI-stderr:", packet.b);
24625 -                       
24626 +
24627                         break;
24628                 case FCGI_END_REQUEST:
24629                         con->file_finished = 1;
24630 -                       
24631 +
24632                         if (host->mode != FCGI_AUTHORIZER ||
24633                             !(con->http_status == 0 ||
24634                               con->http_status == 200)) {
24635 @@ -2547,39 +2424,39 @@
24636                                 http_chunk_append_mem(srv, con, NULL, 0);
24637                                 joblist_append(srv, con);
24638                         }
24639 -                       
24640 +
24641                         fin = 1;
24642                         break;
24643                 default:
24644 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
24645 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
24646                                         "FastCGI: header.type not handled: ", packet.type);
24647                         break;
24648                 }
24649                 buffer_free(packet.b);
24650         }
24651 -       
24652 +
24653         return fin;
24654  }
24655  
24656  static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_host *host) {
24657         fcgi_proc *proc;
24658 -       
24659 +
24660         for (proc = host->first; proc; proc = proc->next) {
24661                 int status;
24662  
24663                 if (p->conf.debug > 2) {
24664 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdddd", 
24665 -                                       "proc:", 
24666 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdddd",
24667 +                                       "proc:",
24668                                         proc->connection_name,
24669                                         proc->state,
24670                                         proc->is_local,
24671                                         proc->load,
24672                                         proc->pid);
24673                 }
24674 -               
24675 -               /* 
24676 +
24677 +               /*
24678                  * if the remote side is overloaded, we check back after <n> seconds
24679 -                * 
24680 +                *
24681                  */
24682                 switch (proc->state) {
24683                 case PROC_STATE_KILLED:
24684 @@ -2592,13 +2469,13 @@
24685                         break;
24686                 case PROC_STATE_OVERLOADED:
24687                         if (srv->cur_ts <= proc->disabled_until) break;
24688 -                       
24689 +
24690                         proc->state = PROC_STATE_RUNNING;
24691                         host->active_procs++;
24692 -                       
24693 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", 
24694 -                                       "fcgi-server re-enabled:", 
24695 -                                       host->host, host->port, 
24696 +
24697 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdb",
24698 +                                       "fcgi-server re-enabled:",
24699 +                                       host->host, host->port,
24700                                         host->unixsocket);
24701                         break;
24702                 case PROC_STATE_DIED_WAIT_FOR_PID:
24703 @@ -2606,7 +2483,7 @@
24704                         if (!proc->is_local) break;
24705  
24706                         /* the child should not terminate at all */
24707 -                       
24708 +#ifndef _WIN32
24709                         switch(waitpid(proc->pid, &status, WNOHANG)) {
24710                         case 0:
24711                                 /* child is still alive */
24712 @@ -2616,45 +2493,45 @@
24713                         default:
24714                                 if (WIFEXITED(status)) {
24715  #if 0
24716 -                                       log_error_write(srv, __FILE__, __LINE__, "sdsd", 
24717 +                                       log_error_write(srv, __FILE__, __LINE__, "sdsd",
24718                                                         "child exited, pid:", proc->pid,
24719                                                         "status:", WEXITSTATUS(status));
24720  #endif
24721                                 } else if (WIFSIGNALED(status)) {
24722 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
24723 -                                                       "child signaled:", 
24724 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
24725 +                                                       "child signaled:",
24726                                                         WTERMSIG(status));
24727                                 } else {
24728 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
24729 -                                                       "child died somehow:", 
24730 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
24731 +                                                       "child died somehow:",
24732                                                         status);
24733                                 }
24734 -                               
24735 +
24736                                 proc->state = PROC_STATE_DIED;
24737                                 break;
24738                         }
24739 -
24740 +#endif
24741                         /* fall through if we have a dead proc now */
24742                         if (proc->state != PROC_STATE_DIED) break;
24743  
24744                 case PROC_STATE_DIED:
24745 -                       /* local proc get restarted by us, 
24746 +                       /* local proc get restarted by us,
24747                          * remote ones hopefully by the admin */
24748 -                       
24749 +
24750                         if (proc->is_local) {
24751                                 /* we still have connections bound to this proc,
24752                                  * let them terminate first */
24753                                 if (proc->load != 0) break;
24754 -                       
24755 +
24756                                 /* restart the child */
24757 -                               
24758 +
24759                                 if (p->conf.debug) {
24760                                         log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
24761                                                         "--- fastcgi spawning",
24762                                                         "\n\tsocket", proc->connection_name,
24763                                                         "\n\tcurrent:", 1, "/", host->min_procs);
24764                                 }
24765 -                               
24766 +
24767                                 if (fcgi_spawn_connection(srv, p, host, proc)) {
24768                                         log_error_write(srv, __FILE__, __LINE__, "s",
24769                                                         "ERROR: spawning fcgi failed.");
24770 @@ -2662,18 +2539,18 @@
24771                                 }
24772                         } else {
24773                                 if (srv->cur_ts <= proc->disabled_until) break;
24774 -                       
24775 +
24776                                 proc->state = PROC_STATE_RUNNING;
24777                                 host->active_procs++;
24778 -                       
24779 -                               log_error_write(srv, __FILE__, __LINE__,  "sb", 
24780 -                                               "fcgi-server re-enabled:", 
24781 +
24782 +                               log_error_write(srv, __FILE__, __LINE__,  "sb",
24783 +                                               "fcgi-server re-enabled:",
24784                                                 proc->connection_name);
24785                         }
24786                         break;
24787                 }
24788         }
24789 -       
24790 +
24791         return 0;
24792  }
24793  
24794 @@ -2682,19 +2559,19 @@
24795         fcgi_extension_host *host= hctx->host;
24796         connection *con   = hctx->remote_conn;
24797         fcgi_proc  *proc;
24798 -       
24799 +
24800         int ret;
24801  
24802 -       /* sanity check */      
24803 +       /* sanity check */
24804         if (!host ||
24805             ((!host->host->used || !host->port) && !host->unixsocket->used)) {
24806 -               log_error_write(srv, __FILE__, __LINE__, "sxddd", 
24807 +               log_error_write(srv, __FILE__, __LINE__, "sxddd",
24808                                 "write-req: error",
24809                                 host,
24810                                 host->host->used,
24811                                 host->port,
24812                                 host->unixsocket->used);
24813 -                       
24814 +
24815                 hctx->proc->disabled_until = srv->cur_ts + 10;
24816                 hctx->proc->state = PROC_STATE_DIED;
24817  
24818 @@ -2705,12 +2582,12 @@
24819         if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
24820                 int socket_error;
24821                 socklen_t socket_error_len = sizeof(socket_error);
24822 -                       
24823 +
24824                 /* try to finish the connect() */
24825 -               if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
24826 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
24827 +               if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
24828 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
24829                                         "getsockopt failed:", strerror(errno));
24830 -                       
24831 +
24832                         hctx->proc->disabled_until = srv->cur_ts + 10;
24833                         hctx->proc->state = PROC_STATE_DIED;
24834  
24835 @@ -2719,12 +2596,12 @@
24836                 if (socket_error != 0) {
24837                         if (!hctx->proc->is_local || p->conf.debug) {
24838                                 /* local procs get restarted */
24839 -                               
24840 +
24841                                 log_error_write(srv, __FILE__, __LINE__, "sssb",
24842 -                                               "establishing connection failed:", strerror(socket_error), 
24843 +                                               "establishing connection failed:", strerror(socket_error),
24844                                                 "socket:", hctx->proc->connection_name);
24845                         }
24846 -       
24847 +
24848                         hctx->proc->disabled_until = srv->cur_ts + 5;
24849  
24850                         if (hctx->proc->is_local) {
24851 @@ -2732,17 +2609,17 @@
24852                         } else {
24853                                 hctx->proc->state = PROC_STATE_DIED;
24854                         }
24855 -       
24856 +
24857                         hctx->proc->state = PROC_STATE_DIED;
24858 -               
24859 +
24860                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
24861                         buffer_append_string(p->statuskey, ".died");
24862  
24863 -                       status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
24864 -               
24865 +                       status_counter_inc(CONST_BUF_LEN(p->statuskey));
24866 +
24867                         return HANDLER_ERROR;
24868                 }
24869 -               /* go on with preparing the request */ 
24870 +               /* go on with preparing the request */
24871                 hctx->state = FCGI_STATE_PREPARE_WRITE;
24872         }
24873  
24874 @@ -2755,14 +2632,14 @@
24875                 /* do we have a running process for this host (max-procs) ? */
24876                 hctx->proc = NULL;
24877  
24878 -               for (proc = hctx->host->first; 
24879 -                    proc && proc->state != PROC_STATE_RUNNING; 
24880 +               for (proc = hctx->host->first;
24881 +                    proc && proc->state != PROC_STATE_RUNNING;
24882                      proc = proc->next);
24883 -                       
24884 +
24885                 /* all childs are dead */
24886                 if (proc == NULL) {
24887 -                       hctx->fde_ndx = -1;
24888 -               
24889 +                       hctx->sock->fde_ndx = -1;
24890 +
24891                         return HANDLER_ERROR;
24892                 }
24893  
24894 @@ -2775,50 +2652,50 @@
24895                 }
24896  
24897                 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
24898 -               
24899 -               if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
24900 +
24901 +               if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
24902                         if (errno == EMFILE ||
24903                             errno == EINTR) {
24904 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
24905 -                                               "wait for fd at connection:", con->fd);
24906 -                               
24907 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
24908 +                                               "wait for fd at connection:", con->sock->fd);
24909 +
24910                                 return HANDLER_WAIT_FOR_FD;
24911                         }
24912 -                       
24913 -                       log_error_write(srv, __FILE__, __LINE__, "ssdd", 
24914 +
24915 +                       log_error_write(srv, __FILE__, __LINE__, "ssdd",
24916                                         "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
24917                         return HANDLER_ERROR;
24918                 }
24919 -               hctx->fde_ndx = -1;
24920 -               
24921 +               hctx->sock->fde_ndx = -1;
24922 +
24923                 srv->cur_fds++;
24924 -               
24925 -               fdevent_register(srv->ev, hctx->fd, fcgi_handle_fdevent, hctx);
24926 -               
24927 -               if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
24928 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
24929 +
24930 +               fdevent_register(srv->ev, hctx->sock, fcgi_handle_fdevent, hctx);
24931 +
24932 +               if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
24933 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
24934                                         "fcntl failed:", strerror(errno));
24935 -                       
24936 +
24937                         return HANDLER_ERROR;
24938                 }
24939 -                       
24940 +
24941                 if (hctx->proc->is_local) {
24942                         hctx->pid = hctx->proc->pid;
24943                 }
24944 -                       
24945 +
24946                 switch (fcgi_establish_connection(srv, hctx)) {
24947                 case CONNECTION_DELAYED:
24948                         /* connection is in progress, wait for an event and call getsockopt() below */
24949 -                       
24950 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
24951 -                       
24952 +
24953 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
24954 +
24955                         fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT_DELAYED);
24956                         return HANDLER_WAIT_FOR_EVENT;
24957                 case CONNECTION_OVERLOADED:
24958                         /* cool down the backend, it is overloaded
24959                          * -> EAGAIN */
24960  
24961 -                       log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
24962 +                       log_error_write(srv, __FILE__, __LINE__, "ssdsd",
24963                                 "backend is overloaded, we disable it for a 2 seconds and send the request to another backend instead:",
24964                                 "reconnects:", hctx->reconnects,
24965                                 "load:", host->load);
24966 @@ -2830,8 +2707,8 @@
24967                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
24968                         buffer_append_string(p->statuskey, ".overloaded");
24969  
24970 -                       status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
24971 -                       
24972 +                       status_counter_inc(CONST_BUF_LEN(p->statuskey));
24973 +
24974                         return HANDLER_ERROR;
24975                 case CONNECTION_DEAD:
24976                         /* we got a hard error from the backend like
24977 @@ -2840,67 +2717,67 @@
24978                          *
24979                          * for check if the host is back in 5 seconds
24980                          *  */
24981 -                       
24982 +
24983                         hctx->proc->disabled_until = srv->cur_ts + 5;
24984                         if (hctx->proc->is_local) {
24985                                 hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
24986                         } else {
24987                                 hctx->proc->state = PROC_STATE_DIED;
24988                         }
24989 -       
24990 -                       log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
24991 +
24992 +                       log_error_write(srv, __FILE__, __LINE__, "ssdsd",
24993                                 "backend died, we disable it for a 5 seconds and send the request to another backend instead:",
24994                                 "reconnects:", hctx->reconnects,
24995                                 "load:", host->load);
24996 -       
24997 +
24998                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
24999                         buffer_append_string(p->statuskey, ".died");
25000  
25001 -                       status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
25002 +                       status_counter_inc(CONST_BUF_LEN(p->statuskey));
25003  
25004                         return HANDLER_ERROR;
25005                 case CONNECTION_OK:
25006                         /* everything is ok, go on */
25007  
25008                         fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
25009 -                       
25010 +
25011                         break;
25012                 case CONNECTION_UNSET:
25013                         break;
25014                 }
25015 -               
25016 +
25017         case FCGI_STATE_PREPARE_WRITE:
25018                 /* ok, we have the connection */
25019 -               
25020 +
25021                 hctx->proc->load++;
25022                 hctx->proc->last_used = srv->cur_ts;
25023                 hctx->got_proc = 1;
25024 -       
25025 -               status_counter_inc(srv, CONST_STR_LEN("fastcgi.requests"));
25026 -               status_counter_inc(srv, CONST_STR_LEN("fastcgi.active-requests"));
25027 +
25028 +               status_counter_inc(CONST_STR_LEN("fastcgi.requests"));
25029 +               status_counter_inc(CONST_STR_LEN("fastcgi.active-requests"));
25030  
25031                 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
25032                 buffer_append_string(p->statuskey, ".connected");
25033  
25034 -               status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
25035 +               status_counter_inc(CONST_BUF_LEN(p->statuskey));
25036  
25037                 /* the proc-load */
25038                 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
25039                 buffer_append_string(p->statuskey, ".load");
25040  
25041 -               status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
25042 +               status_counter_set(CONST_BUF_LEN(p->statuskey), hctx->proc->load);
25043  
25044                 /* the host-load */
25045                 fastcgi_status_copy_procname(p->statuskey, hctx->host, NULL);
25046                 buffer_append_string(p->statuskey, ".load");
25047  
25048 -               status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->host->load);
25049 +               status_counter_set(CONST_BUF_LEN(p->statuskey), hctx->host->load);
25050  
25051                 if (p->conf.debug) {
25052                         log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
25053 -                                       "got proc:", 
25054 -                                       "pid:", hctx->proc->pid, 
25055 -                                       "socket:", hctx->proc->connection_name, 
25056 +                                       "got proc:",
25057 +                                       "pid:", hctx->proc->pid,
25058 +                                       "socket:", hctx->proc->connection_name,
25059                                         "load:", hctx->proc->load);
25060                 }
25061  
25062 @@ -2908,74 +2785,75 @@
25063                 if (hctx->request_id == 0) {
25064                         hctx->request_id = fcgi_requestid_new(srv, p);
25065                 } else {
25066 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
25067 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
25068                                         "fcgi-request is already in use:", hctx->request_id);
25069                 }
25070 -               
25071 +
25072                 /* fall through */
25073                 fcgi_create_env(srv, hctx, hctx->request_id);
25074 -               
25075 +
25076                 fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);
25077 -               
25078 +
25079                 /* fall through */
25080         case FCGI_STATE_WRITE:
25081 -               ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); 
25082 +               ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
25083  
25084                 chunkqueue_remove_finished_chunks(hctx->wb);
25085 -               
25086 +
25087                 if (ret < 0) {
25088                         switch(errno) {
25089                         case ENOTCONN:
25090 -                               /* the connection got dropped after accept() 
25091 -                                * 
25092 -                                * this is most of the time a PHP which dies 
25093 +                               /* the connection got dropped after accept()
25094 +                                *
25095 +                                * this is most of the time a PHP which dies
25096                                  * after PHP_FCGI_MAX_REQUESTS
25097 -                                * 
25098 -                                */ 
25099 +                                *
25100 +                                */
25101                                 if (hctx->wb->bytes_out == 0 &&
25102                                     hctx->reconnects < 5) {
25103 -                                       usleep(10000); /* take away the load of the webserver 
25104 -                                                       * to let the php a chance to restart 
25105 +#ifndef _WIN32
25106 +                                       usleep(10000); /* take away the load of the webserver
25107 +                                                       * to let the php a chance to restart
25108                                                         */
25109 -                                       
25110 +#endif
25111                                         fcgi_reconnect(srv, hctx);
25112 -                               
25113 +
25114                                         return HANDLER_WAIT_FOR_FD;
25115                                 }
25116 -                               
25117 +
25118                                 /* not reconnected ... why
25119 -                                * 
25120 +                                *
25121                                  * far@#lighttpd report this for FreeBSD
25122 -                                * 
25123 +                                *
25124                                  */
25125 -                               
25126 -                               log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
25127 +
25128 +                               log_error_write(srv, __FILE__, __LINE__, "ssosd",
25129                                                 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
25130                                                 "write-offset:", hctx->wb->bytes_out,
25131                                                 "reconnect attempts:", hctx->reconnects);
25132 -                               
25133 +
25134                                 return HANDLER_ERROR;
25135                         case EAGAIN:
25136                         case EINTR:
25137 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25138 -                               
25139 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25140 +
25141                                 return HANDLER_WAIT_FOR_EVENT;
25142                         default:
25143 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", 
25144 +                               log_error_write(srv, __FILE__, __LINE__, "ssd",
25145                                                 "write failed:", strerror(errno), errno);
25146 -                               
25147 +
25148                                 return HANDLER_ERROR;
25149                         }
25150                 }
25151  
25152                 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
25153                         /* we don't need the out event anymore */
25154 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
25155 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
25156 +                       fdevent_event_del(srv->ev, hctx->sock);
25157 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
25158                         fcgi_set_state(srv, hctx, FCGI_STATE_READ);
25159                 } else {
25160 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25161 -                               
25162 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25163 +
25164                         return HANDLER_WAIT_FOR_EVENT;
25165                 }
25166  
25167 @@ -2987,7 +2865,7 @@
25168                 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
25169                 return HANDLER_ERROR;
25170         }
25171 -       
25172 +
25173         return HANDLER_WAIT_FOR_EVENT;
25174  }
25175  
25176 @@ -2996,18 +2874,18 @@
25177   * */
25178  SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
25179         plugin_data *p = p_d;
25180 -       
25181 +
25182         handler_ctx *hctx = con->plugin_ctx[p->id];
25183         fcgi_proc *proc;
25184         fcgi_extension_host *host;
25185 -       
25186 +
25187         if (NULL == hctx) return HANDLER_GO_ON;
25188 -       
25189 +
25190         /* not my job */
25191         if (con->mode != p->id) return HANDLER_GO_ON;
25192  
25193         /* we don't have a host yet, choose one
25194 -        * -> this happens in the first round 
25195 +        * -> this happens in the first round
25196          *    and when the host died and we have to select a new one */
25197         if (hctx->host == NULL) {
25198                 size_t k;
25199 @@ -3016,23 +2894,23 @@
25200                 /* get best server */
25201                 for (k = 0, ndx = -1; k < hctx->ext->used; k++) {
25202                         host = hctx->ext->hosts[k];
25203 -               
25204 +
25205                         /* we should have at least one proc that can do something */
25206                         if (host->active_procs == 0) continue;
25207  
25208                         if (used == -1 || host->load < used) {
25209                                 used = host->load;
25210 -                       
25211 +
25212                                 ndx = k;
25213                         }
25214                 }
25215 -       
25216 +
25217                 /* found a server */
25218                 if (ndx == -1) {
25219                         /* all hosts are down */
25220  
25221                         fcgi_connection_close(srv, hctx);
25222 -                       
25223 +
25224                         con->http_status = 500;
25225                         con->mode = DIRECT;
25226  
25227 @@ -3040,16 +2918,16 @@
25228                 }
25229  
25230                 host = hctx->ext->hosts[ndx];
25231 -               
25232 -               /* 
25233 -                * if check-local is disabled, use the uri.path handler 
25234 -                * 
25235 +
25236 +               /*
25237 +                * if check-local is disabled, use the uri.path handler
25238 +                *
25239                  */
25240 -               
25241 +
25242                 /* init handler-context */
25243                 hctx->host = host;
25244  
25245 -               /* we put a connection on this host, move the other new connections to other hosts 
25246 +               /* we put a connection on this host, move the other new connections to other hosts
25247                  *
25248                  * as soon as hctx->host is unassigned, decrease the load again */
25249                 hctx->host->load++;
25250 @@ -3063,7 +2941,7 @@
25251         case HANDLER_ERROR:
25252                 proc = hctx->proc;
25253                 host = hctx->host;
25254 -               
25255 +
25256                 if (hctx->state == FCGI_STATE_INIT ||
25257                     hctx->state == FCGI_STATE_CONNECT_DELAYED) {
25258                         if (proc) host->active_procs--;
25259 @@ -3078,7 +2956,7 @@
25260                                 return HANDLER_WAIT_FOR_FD;
25261                         } else {
25262                                 fcgi_connection_close(srv, hctx);
25263 -                       
25264 +
25265                                 buffer_reset(con->physical.path);
25266                                 con->mode = DIRECT;
25267                                 con->http_status = 500;
25268 @@ -3088,12 +2966,12 @@
25269                         }
25270                 } else {
25271                         fcgi_connection_close(srv, hctx);
25272 -                       
25273 +
25274                         buffer_reset(con->physical.path);
25275                         con->mode = DIRECT;
25276                         con->http_status = 503;
25277                         joblist_append(srv, con); /* really ? */
25278 -                       
25279 +
25280                         return HANDLER_FINISHED;
25281                 }
25282         case HANDLER_WAIT_FOR_EVENT:
25283 @@ -3115,7 +2993,7 @@
25284         handler_ctx *hctx = ctx;
25285         connection  *con  = hctx->remote_conn;
25286         plugin_data *p    = hctx->plugin_data;
25287 -       
25288 +
25289         fcgi_proc *proc   = hctx->proc;
25290         fcgi_extension_host *host= hctx->host;
25291  
25292 @@ -3125,8 +3003,8 @@
25293                 case 0:
25294                         break;
25295                 case 1:
25296 -                       
25297 -                       if (host->mode == FCGI_AUTHORIZER && 
25298 +
25299 +                       if (host->mode == FCGI_AUTHORIZER &&
25300                             (con->http_status == 200 ||
25301                              con->http_status == 0)) {
25302                                 /*
25303 @@ -3136,26 +3014,26 @@
25304                                  */
25305  
25306                                 buffer_copy_string_buffer(con->physical.doc_root, host->docroot);
25307 -                               
25308 +
25309                                 buffer_copy_string_buffer(con->physical.path, host->docroot);
25310                                 buffer_append_string_buffer(con->physical.path, con->uri.path);
25311                                 fcgi_connection_close(srv, hctx);
25312 -                               
25313 +
25314                                 con->mode = DIRECT;
25315                                 con->file_started = 1; /* fcgi_extension won't touch the request afterwards */
25316                         } else {
25317                                 /* we are done */
25318                                 fcgi_connection_close(srv, hctx);
25319                         }
25320 -                       
25321 +
25322                         joblist_append(srv, con);
25323                         return HANDLER_FINISHED;
25324                 case -1:
25325                         if (proc->pid && proc->state != PROC_STATE_DIED) {
25326                                 int status;
25327 -                               
25328 +
25329                                 /* only fetch the zombie if it is not already done */
25330 -                               
25331 +#ifndef _WIN32
25332                                 switch(waitpid(proc->pid, &status, WNOHANG)) {
25333                                 case 0:
25334                                         /* child is still alive */
25335 @@ -3165,60 +3043,61 @@
25336                                 default:
25337                                         /* the child should not terminate at all */
25338                                         if (WIFEXITED(status)) {
25339 -                                               log_error_write(srv, __FILE__, __LINE__, "sdsd", 
25340 +                                               log_error_write(srv, __FILE__, __LINE__, "sdsd",
25341                                                                 "child exited, pid:", proc->pid,
25342                                                                 "status:", WEXITSTATUS(status));
25343                                         } else if (WIFSIGNALED(status)) {
25344 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
25345 -                                                               "child signaled:", 
25346 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
25347 +                                                               "child signaled:",
25348                                                                 WTERMSIG(status));
25349                                         } else {
25350 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
25351 -                                                               "child died somehow:", 
25352 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
25353 +                                                               "child died somehow:",
25354                                                                 status);
25355                                         }
25356 -                                       
25357 +
25358                                         if (p->conf.debug) {
25359                                                 log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
25360                                                                 "--- fastcgi spawning",
25361                                                                 "\n\tsocket", proc->connection_name,
25362                                                                 "\n\tcurrent:", 1, "/", host->min_procs);
25363                                         }
25364 -                                       
25365 +
25366                                         if (fcgi_spawn_connection(srv, p, host, proc)) {
25367                                                 /* respawning failed, retry later */
25368                                                 proc->state = PROC_STATE_DIED;
25369  
25370 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
25371 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
25372                                                                 "respawning failed, will retry later");
25373                                         }
25374 -                                       
25375 +
25376                                         break;
25377                                 }
25378 +#endif
25379                         }
25380  
25381                         if (con->file_started == 0) {
25382                                 /* nothing has been send out yet, try to use another child */
25383 -                               
25384 +
25385                                 if (hctx->wb->bytes_out == 0 &&
25386                                     hctx->reconnects < 5) {
25387                                         fcgi_reconnect(srv, hctx);
25388 -                                       
25389 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbsbs", 
25390 +
25391 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25392                                                 "response not received, request not sent",
25393 -                                               "on socket:", proc->connection_name, 
25394 +                                               "on socket:", proc->connection_name,
25395                                                 "for", con->uri.path, ", reconnecting");
25396 -                                       
25397 +
25398                                         return HANDLER_WAIT_FOR_FD;
25399                                 }
25400 -                       
25401 -                               log_error_write(srv, __FILE__, __LINE__, "sosbsbs", 
25402 +
25403 +                               log_error_write(srv, __FILE__, __LINE__, "sosbsbs",
25404                                                 "response not received, request sent:", hctx->wb->bytes_out,
25405 -                                               "on socket:", proc->connection_name, 
25406 +                                               "on socket:", proc->connection_name,
25407                                                 "for", con->uri.path, ", closing connection");
25408 -                               
25409 +
25410                                 fcgi_connection_close(srv, hctx);
25411 -                               
25412 +
25413                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
25414                                 buffer_reset(con->physical.path);
25415                                 con->http_status = 500;
25416 @@ -3226,76 +3105,76 @@
25417                         } else {
25418                                 /* response might have been already started, kill the connection */
25419                                 fcgi_connection_close(srv, hctx);
25420 -                               
25421 -                               log_error_write(srv, __FILE__, __LINE__, "ssbsbs", 
25422 +
25423 +                               log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25424                                                 "response already sent out, but backend returned error",
25425 -                                               "on socket:", proc->connection_name, 
25426 +                                               "on socket:", proc->connection_name,
25427                                                 "for", con->uri.path, ", terminating connection");
25428 -                               
25429 +
25430                                 connection_set_state(srv, con, CON_STATE_ERROR);
25431                         }
25432  
25433                         /* */
25434 -                       
25435 -                       
25436 +
25437 +
25438                         joblist_append(srv, con);
25439                         return HANDLER_FINISHED;
25440                 }
25441         }
25442 -       
25443 +
25444         if (revents & FDEVENT_OUT) {
25445                 if (hctx->state == FCGI_STATE_CONNECT_DELAYED ||
25446                     hctx->state == FCGI_STATE_WRITE) {
25447                         /* we are allowed to send something out
25448 -                        * 
25449 +                        *
25450                          * 1. in a unfinished connect() call
25451                          * 2. in a unfinished write() call (long POST request)
25452                          */
25453                         return mod_fastcgi_handle_subrequest(srv, con, p);
25454                 } else {
25455 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
25456 -                                       "got a FDEVENT_OUT and didn't know why:", 
25457 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
25458 +                                       "got a FDEVENT_OUT and didn't know why:",
25459                                         hctx->state);
25460                 }
25461         }
25462 -       
25463 +
25464         /* perhaps this issue is already handled */
25465         if (revents & FDEVENT_HUP) {
25466                 if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
25467                         /* getoptsock will catch this one (right ?)
25468 -                        * 
25469 -                        * if we are in connect we might get a EINPROGRESS 
25470 -                        * in the first call and a FDEVENT_HUP in the 
25471 +                        *
25472 +                        * if we are in connect we might get a EINPROGRESS
25473 +                        * in the first call and a FDEVENT_HUP in the
25474                          * second round
25475 -                        * 
25476 +                        *
25477                          * FIXME: as it is a bit ugly.
25478 -                        * 
25479 +                        *
25480                          */
25481                         return mod_fastcgi_handle_subrequest(srv, con, p);
25482                 } else if (hctx->state == FCGI_STATE_READ &&
25483                            hctx->proc->port == 0) {
25484                         /* FIXME:
25485 -                        * 
25486 +                        *
25487                          * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
25488                          * even if the FCGI_FIN packet is not received yet
25489                          */
25490                 } else {
25491 -                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd", 
25492 -                                       "error: unexpected close of fastcgi connection for", 
25493 +                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
25494 +                                       "error: unexpected close of fastcgi connection for",
25495                                         con->uri.path,
25496 -                                       "(no fastcgi process on host:", 
25497 +                                       "(no fastcgi process on host:",
25498                                         host->host,
25499 -                                       ", port: ", 
25500 +                                       ", port: ",
25501                                         host->port,
25502                                         " ?)",
25503                                         hctx->state);
25504 -                       
25505 +
25506                         connection_set_state(srv, con, CON_STATE_ERROR);
25507                         fcgi_connection_close(srv, hctx);
25508                         joblist_append(srv, con);
25509                 }
25510         } else if (revents & FDEVENT_ERR) {
25511 -               log_error_write(srv, __FILE__, __LINE__, "s", 
25512 +               log_error_write(srv, __FILE__, __LINE__, "s",
25513                                 "fcgi: got a FDEVENT_ERR. Don't know why.");
25514                 /* kill all connections to the fastcgi process */
25515  
25516 @@ -3304,45 +3183,42 @@
25517                 fcgi_connection_close(srv, hctx);
25518                 joblist_append(srv, con);
25519         }
25520 -       
25521 +
25522         return HANDLER_FINISHED;
25523  }
25524 -#define PATCH(x) \
25525 -       p->conf.x = s->x;
25526 +
25527  static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
25528         size_t i, j;
25529         plugin_config *s = p->config_storage[0];
25530 -       
25531 -       PATCH(exts);
25532 -       PATCH(debug);
25533 -       PATCH(ext_mapping);
25534 -       
25535 +
25536 +       PATCH_OPTION(exts);
25537 +       PATCH_OPTION(debug);
25538 +       PATCH_OPTION(ext_mapping);
25539 +
25540         /* skip the first, the global context */
25541         for (i = 1; i < srv->config_context->used; i++) {
25542                 data_config *dc = (data_config *)srv->config_context->data[i];
25543                 s = p->config_storage[i];
25544 -               
25545 +
25546                 /* condition didn't match */
25547                 if (!config_check_cond(srv, con, dc)) continue;
25548 -               
25549 +
25550                 /* merge config */
25551                 for (j = 0; j < dc->value->used; j++) {
25552                         data_unset *du = dc->value->data[j];
25553 -                       
25554 +
25555                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.server"))) {
25556 -                               PATCH(exts);
25557 +                               PATCH_OPTION(exts);
25558                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.debug"))) {
25559 -                               PATCH(debug);
25560 +                               PATCH_OPTION(debug);
25561                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.map-extensions"))) {
25562 -                               PATCH(ext_mapping);
25563 +                               PATCH_OPTION(ext_mapping);
25564                         }
25565                 }
25566         }
25567 -       
25568 +
25569         return 0;
25570  }
25571 -#undef PATCH
25572 -
25573  
25574  static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
25575         plugin_data *p = p_d;
25576 @@ -3351,16 +3227,16 @@
25577         buffer *fn;
25578         fcgi_extension *extension = NULL;
25579         fcgi_extension_host *host = NULL;
25580 -       
25581 +
25582         /* Possibly, we processed already this request */
25583         if (con->file_started == 1) return HANDLER_GO_ON;
25584  
25585         fn = uri_path_handler ? con->uri.path : con->physical.path;
25586  
25587         if (buffer_is_empty(fn)) return HANDLER_GO_ON;
25588 -       
25589 +
25590         s_len = fn->used - 1;
25591 -       
25592 +
25593         fcgi_patch_connection(srv, con, p);
25594  
25595         /* fastcgi.map-extensions maps extensions to existing fastcgi.server entries
25596 @@ -3368,24 +3244,24 @@
25597          * fastcgi.map-extensions = ( ".php3" => ".php" )
25598          *
25599          * fastcgi.server = ( ".php" => ... )
25600 -        * 
25601 +        *
25602          * */
25603  
25604         /* check if extension-mapping matches */
25605         for (k = 0; k < p->conf.ext_mapping->used; k++) {
25606                 data_string *ds = (data_string *)p->conf.ext_mapping->data[k];
25607                 size_t ct_len; /* length of the config entry */
25608 -               
25609 +
25610                 if (ds->key->used == 0) continue;
25611 -               
25612 +
25613                 ct_len = ds->key->used - 1;
25614 -               
25615 +
25616                 if (s_len < ct_len) continue;
25617 -               
25618 +
25619                 /* found a mapping */
25620                 if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
25621                         /* check if we know the extension */
25622 -                       
25623 +
25624                         /* we can reuse k here */
25625                         for (k = 0; k < p->conf.exts->used; k++) {
25626                                 extension = p->conf.exts->exts[k];
25627 @@ -3407,15 +3283,15 @@
25628                 /* check if extension matches */
25629                 for (k = 0; k < p->conf.exts->used; k++) {
25630                         size_t ct_len; /* length of the config entry */
25631 -               
25632 +
25633                         extension = p->conf.exts->exts[k];
25634 -               
25635 +
25636                         if (extension->key->used == 0) continue;
25637 -               
25638 +
25639                         ct_len = extension->key->used - 1;
25640 -               
25641 +
25642                         if (s_len < ct_len) continue;
25643 -               
25644 +
25645                         /* check extension in the form "/fcgi_pattern" */
25646                         if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
25647                                 break;
25648 @@ -3441,10 +3317,10 @@
25649                         continue;
25650                 }
25651  
25652 -               /* we found one host that is alive */ 
25653 +               /* we found one host that is alive */
25654                 break;
25655         }
25656 -       
25657 +
25658         if (!host) {
25659                 /* sorry, we don't have a server alive for this ext */
25660                 buffer_reset(con->physical.path);
25661 @@ -3459,72 +3335,72 @@
25662                                         "on", extension->key,
25663                                         "are down.");
25664                 }
25665 -               
25666 +
25667                 return HANDLER_FINISHED;
25668         }
25669  
25670         /* a note about no handler is not sent yey */
25671         extension->note_is_sent = 0;
25672  
25673 -       /* 
25674 -        * if check-local is disabled, use the uri.path handler 
25675 -        * 
25676 +       /*
25677 +        * if check-local is disabled, use the uri.path handler
25678 +        *
25679          */
25680 -       
25681 +
25682         /* init handler-context */
25683         if (uri_path_handler) {
25684                 if (host->check_local == 0) {
25685                         handler_ctx *hctx;
25686                         char *pathinfo;
25687 -                       
25688 +
25689                         hctx = handler_ctx_init();
25690 -                       
25691 +
25692                         hctx->remote_conn      = con;
25693                         hctx->plugin_data      = p;
25694                         hctx->proc             = NULL;
25695                         hctx->ext              = extension;
25696 -       
25697 +
25698  
25699                         hctx->conf.exts        = p->conf.exts;
25700                         hctx->conf.debug       = p->conf.debug;
25701 -                               
25702 +
25703                         con->plugin_ctx[p->id] = hctx;
25704 -                               
25705 +
25706                         con->mode = p->id;
25707 -                               
25708 +
25709                         if (con->conf.log_request_handling) {
25710 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
25711 +                               log_error_write(srv, __FILE__, __LINE__, "s",
25712                                 "handling it in mod_fastcgi");
25713                         }
25714 -                               
25715 -                       /* the prefix is the SCRIPT_NAME, 
25716 +
25717 +                       /* the prefix is the SCRIPT_NAME,
25718                          * everthing from start to the next slash
25719                          * this is important for check-local = "disable"
25720 -                        * 
25721 +                        *
25722                          * if prefix = /admin.fcgi
25723 -                        * 
25724 +                        *
25725                          * /admin.fcgi/foo/bar
25726 -                        * 
25727 +                        *
25728                          * SCRIPT_NAME = /admin.fcgi
25729                          * PATH_INFO   = /foo/bar
25730 -                        * 
25731 +                        *
25732                          * if prefix = /fcgi-bin/
25733 -                        * 
25734 +                        *
25735                          * /fcgi-bin/foo/bar
25736 -                        * 
25737 +                        *
25738                          * SCRIPT_NAME = /fcgi-bin/foo
25739                          * PATH_INFO   = /bar
25740 -                        * 
25741 +                        *
25742                          */
25743 -                       
25744 +
25745                         /* the rewrite is only done for /prefix/? matches */
25746                         if (extension->key->ptr[0] == '/' &&
25747                             con->uri.path->used > extension->key->used &&
25748                             NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
25749 -                               /* rewrite uri.path and pathinfo */ 
25750 -                               
25751 +                               /* rewrite uri.path and pathinfo */
25752 +
25753                                 buffer_copy_string(con->request.pathinfo, pathinfo);
25754 -                               
25755 +
25756                                 con->uri.path->used -= con->request.pathinfo->used - 1;
25757                                 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
25758                         }
25759 @@ -3532,19 +3408,19 @@
25760         } else {
25761                 handler_ctx *hctx;
25762                 hctx = handler_ctx_init();
25763 -               
25764 +
25765                 hctx->remote_conn      = con;
25766                 hctx->plugin_data      = p;
25767                 hctx->proc             = NULL;
25768                 hctx->ext              = extension;
25769 -               
25770 +
25771                 hctx->conf.exts        = p->conf.exts;
25772                 hctx->conf.debug       = p->conf.debug;
25773 -               
25774 +
25775                 con->plugin_ctx[p->id] = hctx;
25776 -               
25777 +
25778                 con->mode = p->id;
25779 -               
25780 +
25781                 if (con->conf.log_request_handling) {
25782                         log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
25783                 }
25784 @@ -3566,19 +3442,19 @@
25785  JOBLIST_FUNC(mod_fastcgi_handle_joblist) {
25786         plugin_data *p = p_d;
25787         handler_ctx *hctx = con->plugin_ctx[p->id];
25788 -       
25789 +
25790         if (hctx == NULL) return HANDLER_GO_ON;
25791  
25792 -       if (hctx->fd != -1) {
25793 +       if (hctx->sock->fd != -1) {
25794                 switch (hctx->state) {
25795                 case FCGI_STATE_READ:
25796 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
25797 -                       
25798 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
25799 +
25800                         break;
25801                 case FCGI_STATE_CONNECT_DELAYED:
25802                 case FCGI_STATE_WRITE:
25803 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25804 -                       
25805 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25806 +
25807                         break;
25808                 case FCGI_STATE_INIT:
25809                         /* at reconnect */
25810 @@ -3595,7 +3471,7 @@
25811  
25812  static handler_t fcgi_connection_close_callback(server *srv, connection *con, void *p_d) {
25813         plugin_data *p = p_d;
25814 -       
25815 +
25816         fcgi_connection_close(srv, con->plugin_ctx[p->id]);
25817  
25818         return HANDLER_GO_ON;
25819 @@ -3604,16 +3480,39 @@
25820  TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
25821         plugin_data *p = p_d;
25822         size_t i, j, n;
25823 -       
25824 -       
25825 +
25826 +
25827         /* perhaps we should kill a connect attempt after 10-15 seconds
25828 -        * 
25829 +        *
25830          * currently we wait for the TCP timeout which is on Linux 180 seconds
25831 -        * 
25832 -        * 
25833 -        * 
25834 +        *
25835          */
25836  
25837 +       for (i = 0; i < srv->conns->used; i++) {
25838 +               connection *con = srv->conns->ptr[i];
25839 +               handler_ctx *hctx = con->plugin_ctx[p->id];
25840 +
25841 +               /* if a connection is ours and is in handle-req for more than max-request-time
25842 +                * kill the connection */
25843 +
25844 +               if (con->mode != p->id) continue;
25845 +               if (con->state != CON_STATE_HANDLE_REQUEST) continue;
25846 +               if (srv->cur_ts < con->request_start + 60) continue;
25847 +
25848 +               /* the request is waiting for a FCGI_STDOUT since 60 seconds */
25849 +
25850 +               /* kill the connection */
25851 +
25852 +               log_error_write(srv, __FILE__, __LINE__, "s", "fastcgi backend didn't responded after 60 seconds");
25853 +
25854 +               fcgi_connection_close(srv, hctx);
25855 +
25856 +               con->mode = DIRECT;
25857 +               con->http_status = 500;
25858 +
25859 +               joblist_append(srv, con);
25860 +       }
25861 +
25862         /* check all childs if they are still up */
25863  
25864         for (i = 0; i < srv->config_context->used; i++) {
25865 @@ -3628,45 +3527,45 @@
25866                         fcgi_extension *ex;
25867  
25868                         ex = exts->exts[j];
25869 -                       
25870 +
25871                         for (n = 0; n < ex->used; n++) {
25872 -                               
25873 +
25874                                 fcgi_proc *proc;
25875                                 unsigned long sum_load = 0;
25876                                 fcgi_extension_host *host;
25877 -                               
25878 +
25879                                 host = ex->hosts[n];
25880 -                               
25881 +
25882                                 fcgi_restart_dead_procs(srv, p, host);
25883 -                               
25884 +
25885                                 for (proc = host->first; proc; proc = proc->next) {
25886                                         sum_load += proc->load;
25887                                 }
25888 -                               
25889 +
25890                                 if (host->num_procs &&
25891                                     host->num_procs < host->max_procs &&
25892                                     (sum_load / host->num_procs) > host->max_load_per_proc) {
25893                                         /* overload, spawn new child */
25894                                         if (p->conf.debug) {
25895 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
25896 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
25897                                                                 "overload detected, spawning a new child");
25898                                         }
25899 -                                       
25900 +
25901                                         for (proc = host->unused_procs; proc && proc->pid != 0; proc = proc->next);
25902 -                                       
25903 +
25904                                         if (proc) {
25905                                                 if (proc == host->unused_procs) host->unused_procs = proc->next;
25906 -                                               
25907 +
25908                                                 if (proc->next) proc->next->prev = NULL;
25909 -                                               
25910 +
25911                                                 host->max_id++;
25912                                         } else {
25913                                                 proc = fastcgi_process_init();
25914                                                 proc->id = host->max_id++;
25915                                         }
25916 -                                       
25917 +
25918                                         host->num_procs++;
25919 -                                       
25920 +
25921                                         if (buffer_is_empty(host->unixsocket)) {
25922                                                 proc->port = host->port + proc->id;
25923                                         } else {
25924 @@ -3674,13 +3573,13 @@
25925                                                 buffer_append_string(proc->unixsocket, "-");
25926                                                 buffer_append_long(proc->unixsocket, proc->id);
25927                                         }
25928 -                                       
25929 +
25930                                         if (fcgi_spawn_connection(srv, p, host, proc)) {
25931                                                 log_error_write(srv, __FILE__, __LINE__, "s",
25932                                                                 "ERROR: spawning fcgi failed.");
25933                                                 return HANDLER_ERROR;
25934                                         }
25935 -                                       
25936 +
25937                                         proc->prev = NULL;
25938                                         proc->next = host->first;
25939                                         if (host->first) {
25940 @@ -3688,56 +3587,56 @@
25941                                         }
25942                                         host->first = proc;
25943                                 }
25944 -                               
25945 +
25946                                 for (proc = host->first; proc; proc = proc->next) {
25947                                         if (proc->load != 0) break;
25948                                         if (host->num_procs <= host->min_procs) break;
25949                                         if (proc->pid == 0) continue;
25950 -                                       
25951 +
25952                                         if (srv->cur_ts - proc->last_used > host->idle_timeout) {
25953                                                 /* a proc is idling for a long time now,
25954                                                  * terminated it */
25955 -                                               
25956 +
25957                                                 if (p->conf.debug) {
25958 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
25959 -                                                                       "idle-timeout reached, terminating child:", 
25960 -                                                                       "socket:", proc->connection_name, 
25961 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd",
25962 +                                                                       "idle-timeout reached, terminating child:",
25963 +                                                                       "socket:", proc->connection_name,
25964                                                                         "pid", proc->pid);
25965                                                 }
25966 -                                               
25967 -                                               
25968 +
25969 +
25970                                                 if (proc->next) proc->next->prev = proc->prev;
25971                                                 if (proc->prev) proc->prev->next = proc->next;
25972 -                                               
25973 +
25974                                                 if (proc->prev == NULL) host->first = proc->next;
25975 -                                               
25976 +
25977                                                 proc->prev = NULL;
25978                                                 proc->next = host->unused_procs;
25979 -                                               
25980 +
25981                                                 if (host->unused_procs) host->unused_procs->prev = proc;
25982                                                 host->unused_procs = proc;
25983 -                                               
25984 +
25985                                                 kill(proc->pid, SIGTERM);
25986 -                                               
25987 +
25988                                                 proc->state = PROC_STATE_KILLED;
25989 -                                               
25990 -                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
25991 -                                                                       "killed:", 
25992 -                                                                       "socket:", proc->connection_name, 
25993 +
25994 +                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd",
25995 +                                                                       "killed:",
25996 +                                                                       "socket:", proc->connection_name,
25997                                                                         "pid", proc->pid);
25998 -                                               
25999 +
26000                                                 host->num_procs--;
26001 -                                               
26002 +
26003                                                 /* proc is now in unused, let the next second handle the next process */
26004                                                 break;
26005 -                                       }       
26006 +                                       }
26007                                 }
26008 -                               
26009 +
26010                                 for (proc = host->unused_procs; proc; proc = proc->next) {
26011                                         int status;
26012 -                                       
26013 +
26014                                         if (proc->pid == 0) continue;
26015 -                                       
26016 +#ifndef _WIN32
26017                                         switch (waitpid(proc->pid, &status, WNOHANG)) {
26018                                         case 0:
26019                                                 /* child still running after timeout, good */
26020 @@ -3745,10 +3644,10 @@
26021                                         case -1:
26022                                                 if (errno != EINTR) {
26023                                                         /* no PID found ? should never happen */
26024 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddss", 
26025 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddss",
26026                                                                         "pid ", proc->pid, proc->state,
26027                                                                         "not found:", strerror(errno));
26028 -                                                       
26029 +
26030  #if 0
26031                                                         if (errno == ECHILD) {
26032                                                                 /* someone else has cleaned up for us */
26033 @@ -3762,25 +3661,26 @@
26034                                                 /* the child should not terminate at all */
26035                                                 if (WIFEXITED(status)) {
26036                                                         if (proc->state != PROC_STATE_KILLED) {
26037 -                                                               log_error_write(srv, __FILE__, __LINE__, "sdb", 
26038 -                                                                               "child exited:", 
26039 +                                                               log_error_write(srv, __FILE__, __LINE__, "sdb",
26040 +                                                                               "child exited:",
26041                                                                                 WEXITSTATUS(status), proc->connection_name);
26042                                                         }
26043                                                 } else if (WIFSIGNALED(status)) {
26044                                                         if (WTERMSIG(status) != SIGTERM) {
26045 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
26046 -                                                                               "child signaled:", 
26047 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
26048 +                                                                               "child signaled:",
26049                                                                                 WTERMSIG(status));
26050                                                         }
26051                                                 } else {
26052 -                                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
26053 -                                                                       "child died somehow:", 
26054 +                                                       log_error_write(srv, __FILE__, __LINE__, "sd",
26055 +                                                                       "child died somehow:",
26056                                                                         status);
26057                                                 }
26058                                                 proc->pid = 0;
26059                                                 proc->state = PROC_STATE_UNSET;
26060                                                 host->max_id--;
26061                                         }
26062 +#endif
26063                                 }
26064                         }
26065                 }
26066 @@ -3804,8 +3704,8 @@
26067         p->handle_subrequest       = mod_fastcgi_handle_subrequest;
26068         p->handle_joblist          = mod_fastcgi_handle_joblist;
26069         p->handle_trigger          = mod_fastcgi_handle_trigger;
26070 -       
26071 +
26072         p->data         = NULL;
26073 -       
26074 +
26075         return 0;
26076  }
26077 --- ../lighttpd-1.4.11/src/mod_flv_streaming.c  2006-03-07 14:06:26.000000000 +0200
26078 +++ lighttpd-1.4.12/src/mod_flv_streaming.c     2006-07-16 00:26:04.000000000 +0300
26079 @@ -23,35 +23,35 @@
26080  
26081  typedef struct {
26082         PLUGIN_DATA;
26083 -       
26084 +
26085         buffer *query_str;
26086         array *get_params;
26087 -       
26088 +
26089         plugin_config **config_storage;
26090 -       
26091 -       plugin_config conf; 
26092 +
26093 +       plugin_config conf;
26094  } plugin_data;
26095  
26096  /* init the plugin data */
26097  INIT_FUNC(mod_flv_streaming_init) {
26098         plugin_data *p;
26099 -       
26100 +
26101         p = calloc(1, sizeof(*p));
26102 -       
26103 +
26104         p->query_str = buffer_init();
26105         p->get_params = array_init();
26106 -       
26107 +
26108         return p;
26109  }
26110  
26111  /* detroy the plugin data */
26112  FREE_FUNC(mod_flv_streaming_free) {
26113         plugin_data *p = p_d;
26114 -       
26115 +
26116         UNUSED(srv);
26117  
26118         if (!p) return HANDLER_GO_ON;
26119 -       
26120 +
26121         if (p->config_storage) {
26122                 size_t i;
26123  
26124 @@ -59,19 +59,19 @@
26125                         plugin_config *s = p->config_storage[i];
26126  
26127                         if (!s) continue;
26128 -                       
26129 +
26130                         array_free(s->extensions);
26131 -                       
26132 +
26133                         free(s);
26134                 }
26135                 free(p->config_storage);
26136         }
26137 -       
26138 +
26139         buffer_free(p->query_str);
26140         array_free(p->get_params);
26141 -       
26142 +
26143         free(p);
26144 -       
26145 +
26146         return HANDLER_GO_ON;
26147  }
26148  
26149 @@ -80,83 +80,80 @@
26150  SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) {
26151         plugin_data *p = p_d;
26152         size_t i = 0;
26153 -       
26154 -       config_values_t cv[] = { 
26155 +
26156 +       config_values_t cv[] = {
26157                 { "flv-streaming.extensions",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
26158                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26159         };
26160 -       
26161 +
26162         if (!p) return HANDLER_ERROR;
26163 -       
26164 +
26165         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26166 -       
26167 +
26168         for (i = 0; i < srv->config_context->used; i++) {
26169                 plugin_config *s;
26170 -               
26171 +
26172                 s = calloc(1, sizeof(plugin_config));
26173                 s->extensions     = array_init();
26174 -               
26175 +
26176                 cv[0].destination = s->extensions;
26177 -               
26178 +
26179                 p->config_storage[i] = s;
26180 -       
26181 +
26182                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
26183                         return HANDLER_ERROR;
26184                 }
26185         }
26186 -       
26187 +
26188         return HANDLER_GO_ON;
26189  }
26190  
26191 -#define PATCH(x) \
26192 -       p->conf.x = s->x;
26193  static int mod_flv_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
26194         size_t i, j;
26195         plugin_config *s = p->config_storage[0];
26196 -       
26197 -       PATCH(extensions);
26198 -       
26199 +
26200 +       PATCH_OPTION(extensions);
26201 +
26202         /* skip the first, the global context */
26203         for (i = 1; i < srv->config_context->used; i++) {
26204                 data_config *dc = (data_config *)srv->config_context->data[i];
26205                 s = p->config_storage[i];
26206 -               
26207 +
26208                 /* condition didn't match */
26209                 if (!config_check_cond(srv, con, dc)) continue;
26210 -               
26211 +
26212                 /* merge config */
26213                 for (j = 0; j < dc->value->used; j++) {
26214                         data_unset *du = dc->value->data[j];
26215 -                       
26216 +
26217                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("flv-streaming.extensions"))) {
26218 -                               PATCH(extensions);
26219 +                               PATCH_OPTION(extensions);
26220                         }
26221                 }
26222         }
26223 -       
26224 +
26225         return 0;
26226  }
26227 -#undef PATCH
26228  
26229 -static int split_get_params(server *srv, connection *con, array *get_params, buffer *qrystr) {
26230 +static int split_get_params(array *get_params, buffer *qrystr) {
26231         size_t is_key = 1;
26232         size_t i;
26233         char *key = NULL, *val = NULL;
26234 -       
26235 +
26236         key = qrystr->ptr;
26237 -       
26238 +
26239         /* we need the \0 */
26240         for (i = 0; i < qrystr->used; i++) {
26241                 switch(qrystr->ptr[i]) {
26242                 case '=':
26243                         if (is_key) {
26244                                 val = qrystr->ptr + i + 1;
26245 -                               
26246 +
26247                                 qrystr->ptr[i] = '\0';
26248 -                               
26249 +
26250                                 is_key = 0;
26251                         }
26252 -                       
26253 +
26254                         break;
26255                 case '&':
26256                 case '\0': /* fin symbol */
26257 @@ -167,7 +164,7 @@
26258                                 /* terminate the value */
26259                                 qrystr->ptr[i] = '\0';
26260  
26261 -                               if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
26262 +                               if (NULL == (ds = (data_string *)array_get_unused_element(get_params, TYPE_STRING))) {
26263                                         ds = data_string_init();
26264                                 }
26265                                 buffer_copy_string_len(ds->key, key, strlen(key));
26266 @@ -175,14 +172,14 @@
26267  
26268                                 array_insert_unique(get_params, (data_unset *)ds);
26269                         }
26270 -                       
26271 +
26272                         key = qrystr->ptr + i + 1;
26273                         val = NULL;
26274                         is_key = 1;
26275                         break;
26276                 }
26277         }
26278 -       
26279 +
26280         return 0;
26281  }
26282  
26283 @@ -190,34 +187,34 @@
26284         plugin_data *p = p_d;
26285         int s_len;
26286         size_t k;
26287 -       
26288 +
26289         UNUSED(srv);
26290  
26291         if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
26292 -       
26293 +
26294         mod_flv_streaming_patch_connection(srv, con, p);
26295  
26296         s_len = con->physical.path->used - 1;
26297 -       
26298 +
26299         for (k = 0; k < p->conf.extensions->used; k++) {
26300                 data_string *ds = (data_string *)p->conf.extensions->data[k];
26301                 int ct_len = ds->value->used - 1;
26302 -               
26303 +
26304                 if (ct_len > s_len) continue;
26305                 if (ds->value->used == 0) continue;
26306 -               
26307 +
26308                 if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
26309                         data_string *get_param;
26310                         stat_cache_entry *sce = NULL;
26311                         buffer *b;
26312                         int start;
26313                         char *err = NULL;
26314 -                       /* if there is a start=[0-9]+ in the header use it as start, 
26315 +                       /* if there is a start=[0-9]+ in the header use it as start,
26316                          * otherwise send the full file */
26317  
26318                         array_reset(p->get_params);
26319                         buffer_copy_string_buffer(p->query_str, con->uri.query);
26320 -                       split_get_params(srv, con, p->get_params, p->query_str);
26321 +                       split_get_params(p->get_params, p->query_str);
26322  
26323                         if (NULL == (get_param = (data_string *)array_get_element(p->get_params, "start"))) {
26324                                 return HANDLER_GO_ON;
26325 @@ -256,7 +253,7 @@
26326                         return HANDLER_FINISHED;
26327                 }
26328         }
26329 -       
26330 +
26331         /* not found */
26332         return HANDLER_GO_ON;
26333  }
26334 @@ -266,13 +263,13 @@
26335  int mod_flv_streaming_plugin_init(plugin *p) {
26336         p->version     = LIGHTTPD_VERSION_ID;
26337         p->name        = buffer_init_string("flv_streaming");
26338 -       
26339 +
26340         p->init        = mod_flv_streaming_init;
26341         p->handle_physical = mod_flv_streaming_path_handler;
26342         p->set_defaults  = mod_flv_streaming_set_defaults;
26343         p->cleanup     = mod_flv_streaming_free;
26344 -       
26345 +
26346         p->data        = NULL;
26347 -       
26348 +
26349         return 0;
26350  }
26351 --- ../lighttpd-1.4.11/src/mod_indexfile.c      2005-09-30 01:08:53.000000000 +0300
26352 +++ lighttpd-1.4.12/src/mod_indexfile.c 2006-07-16 00:26:04.000000000 +0300
26353 @@ -12,6 +12,8 @@
26354  
26355  #include "stat_cache.h"
26356  
26357 +#include "sys-strings.h"
26358 +#include "sys-files.h"
26359  /* plugin config for all request/connections */
26360  
26361  typedef struct {
26362 @@ -20,51 +22,51 @@
26363  
26364  typedef struct {
26365         PLUGIN_DATA;
26366 -       
26367 +
26368         buffer *tmp_buf;
26369 -       
26370 +
26371         plugin_config **config_storage;
26372 -       
26373 -       plugin_config conf; 
26374 +
26375 +       plugin_config conf;
26376  } plugin_data;
26377  
26378  /* init the plugin data */
26379  INIT_FUNC(mod_indexfile_init) {
26380         plugin_data *p;
26381 -       
26382 +
26383         p = calloc(1, sizeof(*p));
26384 -       
26385 +
26386         p->tmp_buf = buffer_init();
26387 -       
26388 +
26389         return p;
26390  }
26391  
26392  /* detroy the plugin data */
26393  FREE_FUNC(mod_indexfile_free) {
26394         plugin_data *p = p_d;
26395 -       
26396 +
26397         UNUSED(srv);
26398  
26399         if (!p) return HANDLER_GO_ON;
26400 -       
26401 +
26402         if (p->config_storage) {
26403                 size_t i;
26404                 for (i = 0; i < srv->config_context->used; i++) {
26405                         plugin_config *s = p->config_storage[i];
26406  
26407                         if (!s) continue;
26408 -                       
26409 +
26410                         array_free(s->indexfiles);
26411 -                       
26412 +
26413                         free(s);
26414                 }
26415                 free(p->config_storage);
26416         }
26417 -       
26418 +
26419         buffer_free(p->tmp_buf);
26420 -       
26421 +
26422         free(p);
26423 -       
26424 +
26425         return HANDLER_GO_ON;
26426  }
26427  
26428 @@ -73,131 +75,139 @@
26429  SETDEFAULTS_FUNC(mod_indexfile_set_defaults) {
26430         plugin_data *p = p_d;
26431         size_t i = 0;
26432 -       
26433 -       config_values_t cv[] = { 
26434 +
26435 +       config_values_t cv[] = {
26436                 { "index-file.names",           NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
26437                 { "server.indexfiles",          NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
26438                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26439         };
26440 -       
26441 +
26442         if (!p) return HANDLER_ERROR;
26443 -       
26444 +
26445         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26446 -       
26447 +
26448         for (i = 0; i < srv->config_context->used; i++) {
26449                 plugin_config *s;
26450 -               
26451 +
26452                 s = calloc(1, sizeof(plugin_config));
26453                 s->indexfiles    = array_init();
26454 -               
26455 +
26456                 cv[0].destination = s->indexfiles;
26457                 cv[1].destination = s->indexfiles; /* old name for [0] */
26458 -               
26459 +
26460                 p->config_storage[i] = s;
26461 -       
26462 +
26463                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
26464                         return HANDLER_ERROR;
26465                 }
26466         }
26467 -       
26468 +
26469         return HANDLER_GO_ON;
26470  }
26471  
26472 -#define PATCH(x) \
26473 -       p->conf.x = s->x;
26474  static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_data *p) {
26475         size_t i, j;
26476         plugin_config *s = p->config_storage[0];
26477 -       
26478 -       PATCH(indexfiles);
26479 -       
26480 +
26481 +       PATCH_OPTION(indexfiles);
26482 +
26483         /* skip the first, the global context */
26484         for (i = 1; i < srv->config_context->used; i++) {
26485                 data_config *dc = (data_config *)srv->config_context->data[i];
26486                 s = p->config_storage[i];
26487 -               
26488 +
26489                 /* condition didn't match */
26490                 if (!config_check_cond(srv, con, dc)) continue;
26491 -               
26492 +
26493                 /* merge config */
26494                 for (j = 0; j < dc->value->used; j++) {
26495                         data_unset *du = dc->value->data[j];
26496 -                       
26497 +
26498                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.indexfiles"))) {
26499 -                               PATCH(indexfiles);
26500 +                               PATCH_OPTION(indexfiles);
26501                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("index-file.names"))) {
26502 -                               PATCH(indexfiles);
26503 +                               PATCH_OPTION(indexfiles);
26504                         }
26505                 }
26506         }
26507 -       
26508 +
26509         return 0;
26510  }
26511 -#undef PATCH
26512  
26513  URIHANDLER_FUNC(mod_indexfile_subrequest) {
26514         plugin_data *p = p_d;
26515         size_t k;
26516         stat_cache_entry *sce = NULL;
26517 -       
26518 +
26519         if (con->uri.path->used == 0) return HANDLER_GO_ON;
26520         if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
26521 -       
26522 +
26523         mod_indexfile_patch_connection(srv, con, p);
26524 -       
26525 +
26526 +       /* is the physical-path really a dir ? */
26527 +       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
26528 +               return HANDLER_GO_ON;
26529 +       }
26530 +
26531 +       if (!S_ISDIR(sce->st.st_mode)) {
26532 +               return HANDLER_GO_ON;
26533 +       }
26534 +
26535         if (con->conf.log_request_handling) {
26536                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling the request as Indexfile");
26537                 log_error_write(srv, __FILE__, __LINE__,  "sb", "URI          :", con->uri.path);
26538         }
26539 -       
26540 +
26541 +
26542         /* indexfile */
26543         for (k = 0; k < p->conf.indexfiles->used; k++) {
26544                 data_string *ds = (data_string *)p->conf.indexfiles->data[k];
26545 -               
26546 +
26547                 if (ds->value && ds->value->ptr[0] == '/') {
26548 -                       /* if the index-file starts with a prefix as use this file as 
26549 +                       /* if the index-file starts with a prefix as use this file as
26550                          * index-generator */
26551                         buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
26552                 } else {
26553                         buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
26554 +                       PATHNAME_APPEND_SLASH(p->tmp_buf);
26555                 }
26556                 buffer_append_string_buffer(p->tmp_buf, ds->value);
26557 -               
26558 +
26559                 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
26560                         if (errno == EACCES) {
26561                                 con->http_status = 403;
26562                                 buffer_reset(con->physical.path);
26563 -                               
26564 +
26565                                 return HANDLER_FINISHED;
26566                         }
26567 -                       
26568 +
26569                         if (errno != ENOENT &&
26570                             errno != ENOTDIR) {
26571                                 /* we have no idea what happend. let's tell the user so. */
26572 -                               
26573 +
26574                                 con->http_status = 500;
26575 -                               
26576 +
26577                                 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
26578                                                 "file not found ... or so: ", strerror(errno),
26579                                                 con->uri.path,
26580                                                 "->", con->physical.path);
26581 -                               
26582 +
26583                                 buffer_reset(con->physical.path);
26584 -                               
26585 +
26586                                 return HANDLER_FINISHED;
26587                         }
26588                         continue;
26589                 }
26590 -                       
26591 +
26592                 /* rewrite uri.path to the real path (/ -> /index.php) */
26593                 buffer_append_string_buffer(con->uri.path, ds->value);
26594                 buffer_copy_string_buffer(con->physical.path, p->tmp_buf);
26595 -               
26596 +
26597                 /* fce is already set up a few lines above */
26598 -               
26599 +
26600                 return HANDLER_GO_ON;
26601         }
26602 -       
26603 +
26604         /* not found */
26605         return HANDLER_GO_ON;
26606  }
26607 @@ -207,13 +217,13 @@
26608  int mod_indexfile_plugin_init(plugin *p) {
26609         p->version     = LIGHTTPD_VERSION_ID;
26610         p->name        = buffer_init_string("indexfile");
26611 -       
26612 +
26613         p->init        = mod_indexfile_init;
26614         p->handle_subrequest_start = mod_indexfile_subrequest;
26615         p->set_defaults  = mod_indexfile_set_defaults;
26616         p->cleanup     = mod_indexfile_free;
26617 -       
26618 +
26619         p->data        = NULL;
26620 -       
26621 +
26622         return 0;
26623  }
26624 --- ../lighttpd-1.4.11/src/mod_mysql_vhost.c    2006-01-14 20:35:10.000000000 +0200
26625 +++ lighttpd-1.4.12/src/mod_mysql_vhost.c       2006-07-20 00:57:19.000000000 +0300
26626 @@ -1,13 +1,18 @@
26627 -#include <unistd.h>
26628  #include <stdio.h>
26629  #include <errno.h>
26630  #include <fcntl.h>
26631 -#include <strings.h>
26632 +#include <string.h>
26633  
26634  #ifdef HAVE_CONFIG_H
26635  #include "config.h"
26636  #endif
26637  
26638 +#ifdef HAVE_MYSQL_H 
26639 +# ifdef HAVE_LIBMYSQL
26640 +#  define HAVE_MYSQL
26641 +# endif
26642 +#endif
26643 +
26644  #ifdef HAVE_MYSQL
26645  #include <mysql.h>
26646  #endif
26647 @@ -16,61 +21,40 @@
26648  #include "log.h"
26649  
26650  #include "stat_cache.h"
26651 -#ifdef DEBUG_MOD_MYSQL_VHOST
26652 -#define DEBUG
26653 -#endif
26654 +#include "sys-files.h"
26655  
26656 -/*
26657 - * Plugin for lighttpd to use MySQL 
26658 - *   for domain to directory lookups,
26659 - *   i.e virtual hosts (vhosts).
26660 - *   
26661 - * Optionally sets fcgi_offset and fcgi_arg 
26662 - *   in preparation for fcgi.c to handle 
26663 - *   per-user fcgi chroot jails.
26664 - *
26665 - * /ada@riksnet.se 2004-12-06
26666 - */
26667 +#include "mod_sql_vhost_core.h"
26668  
26669  #ifdef HAVE_MYSQL
26670 +
26671 +#define CORE_PLUGIN "mod_sql_vhost_core"
26672 +
26673  typedef struct {
26674         MYSQL   *mysql;
26675 -       
26676 -       buffer  *mydb;
26677 -       buffer  *myuser;
26678 -       buffer  *mypass;
26679 -       buffer  *mysock;
26680 -       
26681 -       buffer  *hostname;
26682 -       unsigned short port;
26683 -       
26684 +
26685         buffer  *mysql_pre;
26686         buffer  *mysql_post;
26687 +
26688 +       mod_sql_vhost_core_plugin_config *core;
26689  } plugin_config;
26690  
26691  /* global plugin data */
26692  typedef struct {
26693         PLUGIN_DATA;
26694 -       
26695 +
26696         buffer  *tmp_buf;
26697 -       
26698 +
26699         plugin_config **config_storage;
26700 -       
26701 -       plugin_config conf; 
26702 +
26703 +       plugin_config conf;
26704  } plugin_data;
26705  
26706 -/* per connection plugin data */
26707 -typedef struct {
26708 -       buffer  *server_name;
26709 -       buffer  *document_root;
26710 -       buffer  *fcgi_arg;
26711 -       unsigned fcgi_offset;
26712 -} plugin_connection_data;
26713 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost); 
26714  
26715  /* init the plugin data */
26716  INIT_FUNC(mod_mysql_vhost_init) {
26717         plugin_data *p;
26718 -       
26719 +
26720         p = calloc(1, sizeof(*p));
26721  
26722         p->tmp_buf = buffer_init();
26723 @@ -83,144 +67,77 @@
26724         plugin_data *p = p_d;
26725  
26726         UNUSED(srv);
26727 -       
26728 -#ifdef DEBUG
26729 -       log_error_write(srv, __FILE__, __LINE__, "ss", 
26730 -               "mod_mysql_vhost_cleanup", p ? "yes" : "NO");
26731 -#endif
26732 +
26733         if (!p) return HANDLER_GO_ON;
26734 -       
26735 +
26736         if (p->config_storage) {
26737                 size_t i;
26738                 for (i = 0; i < srv->config_context->used; i++) {
26739                         plugin_config *s = p->config_storage[i];
26740  
26741                         if (!s) continue;
26742 -                       
26743 +
26744                         mysql_close(s->mysql);
26745 -                       
26746 -                       buffer_free(s->mydb);
26747 -                       buffer_free(s->myuser);
26748 -                       buffer_free(s->mypass);
26749 -                       buffer_free(s->mysock);
26750 +
26751                         buffer_free(s->mysql_pre);
26752                         buffer_free(s->mysql_post);
26753 -                       
26754 +
26755                         free(s);
26756                 }
26757                 free(p->config_storage);
26758         }
26759         buffer_free(p->tmp_buf);
26760 -       
26761 -       free(p);
26762  
26763 -       return HANDLER_GO_ON;
26764 -}
26765 -
26766 -/* handle the plugin per connection data */
26767 -static void* mod_mysql_vhost_connection_data(server *srv, connection *con, void *p_d)
26768 -{
26769 -       plugin_data *p = p_d;
26770 -       plugin_connection_data *c = con->plugin_ctx[p->id];
26771 -
26772 -       UNUSED(srv);
26773 -
26774 -#ifdef DEBUG
26775 -        log_error_write(srv, __FILE__, __LINE__, "ss", 
26776 -               "mod_mysql_connection_data", c ? "old" : "NEW");
26777 -#endif
26778 -
26779 -       if (c) return c;
26780 -       c = calloc(1, sizeof(*c));
26781 -
26782 -       c->server_name = buffer_init();
26783 -       c->document_root = buffer_init();
26784 -       c->fcgi_arg = buffer_init();
26785 -       c->fcgi_offset = 0;
26786 -
26787 -       return con->plugin_ctx[p->id] = c;
26788 -}
26789 -
26790 -/* destroy the plugin per connection data */
26791 -CONNECTION_FUNC(mod_mysql_vhost_handle_connection_close) {
26792 -       plugin_data *p = p_d;
26793 -       plugin_connection_data *c = con->plugin_ctx[p->id];
26794 -
26795 -       UNUSED(srv);
26796 -
26797 -#ifdef DEBUG
26798 -       log_error_write(srv, __FILE__, __LINE__, "ss", 
26799 -               "mod_mysql_vhost_handle_connection_close", c ? "yes" : "NO");
26800 -#endif
26801 -       
26802 -       if (!c) return HANDLER_GO_ON;
26803 -
26804 -       buffer_free(c->server_name);
26805 -       buffer_free(c->document_root);
26806 -       buffer_free(c->fcgi_arg);
26807 -       c->fcgi_offset = 0;
26808 -
26809 -       free(c);
26810 +       free(p);
26811  
26812 -       con->plugin_ctx[p->id] = NULL;
26813         return HANDLER_GO_ON;
26814  }
26815  
26816  /* set configuration values */
26817  SERVER_FUNC(mod_mysql_vhost_set_defaults) {
26818         plugin_data *p = p_d;
26819 +       mod_sql_vhost_core_plugin_data *core_config;
26820  
26821 -       char *qmark;
26822         size_t i = 0;
26823  
26824 -       config_values_t cv[] = {
26825 -               { "mysql-vhost.db",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26826 -               { "mysql-vhost.user",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26827 -               { "mysql-vhost.pass",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26828 -               { "mysql-vhost.sock",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26829 -               { "mysql-vhost.sql",    NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26830 -               { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER },
26831 -               { "mysql-vhost.port",   NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER },
26832 -                { NULL,                        NULL, T_CONFIG_UNSET,   T_CONFIG_SCOPE_UNSET }
26833 -        };
26834 -       
26835 +       /* our very own plugin storage, one entry for each conditional
26836 +        * 
26837 +        * srv->config_context->used is the number of conditionals
26838 +        * */
26839         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26840 -       
26841 +
26842 +       /* get the config of the core-plugin */
26843 +       core_config = plugin_get_config(srv, CORE_PLUGIN);
26844 +
26845 +
26846 +       /* walk through all conditionals and check for assignments */
26847         for (i = 0; i < srv->config_context->used; i++) {
26848                 plugin_config *s;
26849                 buffer *sel;
26850 -               
26851 -               
26852 +               char *qmark;
26853 +
26854 +               /* get the config from the core plugin for this conditional-context */
26855                 s = calloc(1, sizeof(plugin_config));
26856 -               s->mydb = buffer_init();
26857 -               s->myuser = buffer_init();
26858 -               s->mypass = buffer_init();
26859 -               s->mysock = buffer_init();
26860 -               s->hostname = buffer_init();
26861 -               s->port   = 0;               /* default port for mysql */
26862 -               sel = buffer_init();
26863 -               s->mysql = NULL;
26864 +
26865 +               s->core = core_config->config_storage[i];
26866                 
26867 +               s->mysql = NULL;
26868 +
26869                 s->mysql_pre = buffer_init();
26870                 s->mysql_post = buffer_init();
26871 -               
26872 -               cv[0].destination = s->mydb;
26873 -               cv[1].destination = s->myuser;
26874 -               cv[2].destination = s->mypass;
26875 -               cv[3].destination = s->mysock;
26876 -               cv[4].destination = sel;
26877 -               cv[5].destination = s->hostname;
26878 -               cv[6].destination = &(s->port);
26879 -               
26880 +
26881                 p->config_storage[i] = s;
26882 -               
26883 -               if (config_insert_values_global(srv, 
26884 -                       ((data_config *)srv->config_context->data[i])->value,
26885 -                       cv)) return HANDLER_ERROR;
26886 -               
26887 -               s->mysql_pre = buffer_init();
26888 -               s->mysql_post = buffer_init();
26889 -               
26890 +
26891 +               /* check if we are the plugin for this backend */
26892 +               if (!buffer_is_equal_string(s->core->backend, CONST_STR_LEN("mysql"))) continue;
26893 +
26894 +               /* attach us to the core-plugin */
26895 +               s->core->backend_data = p;
26896 +               s->core->get_vhost = mod_mysql_vhost_get_vhost;
26897 +
26898 +               sel = buffer_init();
26899 +               buffer_copy_string_buffer(sel, s->core->select_vhost);
26900 +
26901                 if (sel->used && (qmark = index(sel->ptr, '?'))) {
26902                         *qmark = '\0';
26903                         buffer_copy_string(s->mysql_pre, sel->ptr);
26904 @@ -228,35 +145,38 @@
26905                 } else {
26906                         buffer_copy_string_buffer(s->mysql_pre, sel);
26907                 }
26908 -               
26909 +               buffer_free(sel);
26910 +
26911                 /* required:
26912                  * - username
26913 -                * - database 
26914 -                * 
26915 +                * - database
26916 +                *
26917                  * optional:
26918                  * - password, default: empty
26919                  * - socket, default: mysql default
26920                  * - hostname, if set overrides socket
26921                  * - port, default: 3306
26922                  */
26923 -               
26924 +
26925                 /* all have to be set */
26926 -               if (!(buffer_is_empty(s->myuser) ||
26927 -                     buffer_is_empty(s->mydb))) {
26928 +               if (!(buffer_is_empty(s->core->user) ||
26929 +                     buffer_is_empty(s->core->db))) {
26930  
26931                         int fd;
26932 -               
26933 +
26934                         if (NULL == (s->mysql = mysql_init(NULL))) {
26935                                 log_error_write(srv, __FILE__, __LINE__, "s", "mysql_init() failed, exiting...");
26936 -                               
26937 +
26938                                 return HANDLER_ERROR;
26939                         }
26940 -#define FOO(x) (s->x->used ? s->x->ptr : NULL)
26941 -                       
26942 -                       if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass), 
26943 -                                               FOO(mydb), s->port, FOO(mysock), 0)) {
26944 +#define FOO(x) (s->core->x->used ? s->core->x->ptr : NULL)
26945 +
26946 +                       s->mysql->free_me = 1;
26947 +
26948 +                       if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(user), FOO(pass),
26949 +                                               FOO(db), s->core->port, FOO(sock), 0)) {
26950                                 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(s->mysql));
26951 -                               
26952 +
26953                                 return HANDLER_ERROR;
26954                         }
26955  #undef FOO
26956 @@ -265,61 +185,47 @@
26957                         /* otherwise we cannot be sure that mysql is fd i-1 */
26958                         if (-1 == (fd = open("/dev/null", 0))) {
26959                                 close(fd);
26960 -                               fcntl(fd-1, F_SETFD, FD_CLOEXEC); 
26961 +                               fcntl(fd-1, F_SETFD, FD_CLOEXEC);
26962                         }
26963                 }
26964         }
26965 -       
26966 -       
26967 +
26968 +
26969  
26970          return HANDLER_GO_ON;
26971  }
26972  
26973 -#define PATCH(x) \
26974 -       p->conf.x = s->x;
26975  static int mod_mysql_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
26976 -       size_t i, j;
26977 +       size_t i;
26978         plugin_config *s = p->config_storage[0];
26979 -       
26980 -       PATCH(mysql_pre);
26981 -       PATCH(mysql_post);
26982 -#ifdef HAVE_MYSQL
26983 -       PATCH(mysql);
26984 -#endif
26985 -       
26986 +
26987 +       PATCH_OPTION(mysql_pre);
26988 +       PATCH_OPTION(mysql_post);
26989 +       PATCH_OPTION(mysql);
26990 +
26991         /* skip the first, the global context */
26992         for (i = 1; i < srv->config_context->used; i++) {
26993                 data_config *dc = (data_config *)srv->config_context->data[i];
26994                 s = p->config_storage[i];
26995 -               
26996 +
26997                 /* condition didn't match */
26998                 if (!config_check_cond(srv, con, dc)) continue;
26999 -               
27000 -               /* merge config */
27001 -               for (j = 0; j < dc->value->used; j++) {
27002 -                       data_unset *du = dc->value->data[j];
27003 -                       
27004 -                       if (buffer_is_equal_string(du->key, CONST_STR_LEN("mysql-vhost.sql"))) {
27005 -                               PATCH(mysql_pre);
27006 -                               PATCH(mysql_post);
27007 -                       }
27008 -               }
27009 -               
27010 +
27011                 if (s->mysql) {
27012 -                       PATCH(mysql);
27013 +                       PATCH_OPTION(mysql);
27014 +                       PATCH_OPTION(mysql_pre);
27015 +                       PATCH_OPTION(mysql_post);
27016                 }
27017         }
27018 -       
27019 +
27020         return 0;
27021  }
27022 -#undef PATCH
27023  
27024 -
27025 -/* handle document root request */
27026 -CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
27027 +/**
27028 + * get the vhost info from the database 
27029 + */
27030 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost) {
27031         plugin_data *p = p_d;
27032 -       plugin_connection_data *c;
27033 -       stat_cache_entry *sce;
27034  
27035         unsigned  cols;
27036         MYSQL_ROW row;
27037 @@ -332,13 +238,6 @@
27038  
27039         if (!p->conf.mysql) return HANDLER_GO_ON;
27040  
27041 -       /* sets up connection data if not done yet */
27042 -       c = mod_mysql_vhost_connection_data(srv, con, p_d);
27043 -
27044 -       /* check if cached this connection */
27045 -       if (c->server_name->used && /* con->uri.authority->used && */
27046 -            buffer_is_equal(c->server_name, con->uri.authority)) goto GO_ON;
27047 -
27048         /* build and run SQL query */
27049         buffer_copy_string_buffer(p->tmp_buf, p->conf.mysql_pre);
27050         if (p->conf.mysql_post->used) {
27051 @@ -347,77 +246,43 @@
27052         }
27053         if (mysql_query(p->conf.mysql, p->tmp_buf->ptr)) {
27054                 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(p->conf.mysql));
27055 -               goto ERR500;
27056 +
27057 +               mysql_free_result(result);
27058 +               return HANDLER_GO_ON;
27059         }
27060         result = mysql_store_result(p->conf.mysql);
27061         cols = mysql_num_fields(result);
27062         row = mysql_fetch_row(result);
27063 +
27064         if (!row || cols < 1) {
27065                 /* no such virtual host */
27066                 mysql_free_result(result);
27067                 return HANDLER_GO_ON;
27068         }
27069  
27070 -       /* sanity check that really is a directory */
27071 -       buffer_copy_string(p->tmp_buf, row[0]);
27072 -       BUFFER_APPEND_SLASH(p->tmp_buf);
27073 -
27074 -       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
27075 -               log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
27076 -               goto ERR500;
27077 -       }
27078 -        if (!S_ISDIR(sce->st.st_mode)) {
27079 -               log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->tmp_buf);
27080 -               goto ERR500;
27081 -       }
27082 +       buffer_copy_string(docroot, row[0]);
27083  
27084 -       /* cache the data */
27085 -       buffer_copy_string_buffer(c->server_name, con->uri.authority);
27086 -       buffer_copy_string_buffer(c->document_root, p->tmp_buf);
27087 -
27088 -       /* fcgi_offset and fcgi_arg are optional */
27089 -       if (cols > 1 && row[1]) {
27090 -               c->fcgi_offset = atoi(row[1]);
27091 -               
27092 -               if (cols > 2 && row[2]) {
27093 -                       buffer_copy_string(c->fcgi_arg, row[2]);
27094 -               } else {
27095 -                       c->fcgi_arg->used = 0;
27096 -               }
27097 -       } else {
27098 -               c->fcgi_offset = c->fcgi_arg->used = 0;
27099 -       }
27100         mysql_free_result(result);
27101  
27102 -       /* fix virtual server and docroot */
27103 -GO_ON: buffer_copy_string_buffer(con->server_name, c->server_name);
27104 -       buffer_copy_string_buffer(con->physical.doc_root, c->document_root);
27105 -
27106 -#ifdef DEBUG
27107 -       log_error_write(srv, __FILE__, __LINE__, "sbbdb", 
27108 -               result ? "NOT CACHED" : "cached", 
27109 -               con->server_name, con->physical.doc_root,
27110 -               c->fcgi_offset, c->fcgi_arg);
27111 -#endif
27112 -       return HANDLER_GO_ON;   
27113 -
27114 -ERR500:        if (result) mysql_free_result(result);
27115 -       con->http_status = 500; /* Internal Error */
27116 -       return HANDLER_FINISHED;
27117 +       return HANDLER_GO_ON;
27118  }
27119  
27120  /* this function is called at dlopen() time and inits the callbacks */
27121  int mod_mysql_vhost_plugin_init(plugin *p) {
27122 +       data_string *ds;
27123 +       
27124         p->version     = LIGHTTPD_VERSION_ID;
27125         p->name                         = buffer_init_string("mysql_vhost");
27126  
27127         p->init                         = mod_mysql_vhost_init;
27128         p->cleanup                      = mod_mysql_vhost_cleanup;
27129 -       p->handle_request_done          = mod_mysql_vhost_handle_connection_close;
27130  
27131         p->set_defaults                 = mod_mysql_vhost_set_defaults;
27132 -       p->handle_docroot               = mod_mysql_vhost_handle_docroot;
27133         
27134 +       ds = data_string_init();
27135 +       buffer_copy_string(ds->value, CORE_PLUGIN);
27136 +       array_insert_unique(p->required_plugins, (data_unset *)ds);
27137 +
27138         return 0;
27139  }
27140  #else
27141 --- ../lighttpd-1.4.11/src/mod_proxy.c  2006-01-31 13:01:22.000000000 +0200
27142 +++ lighttpd-1.4.12/src/mod_proxy.c     2006-07-19 20:02:55.000000000 +0300
27143 @@ -1,6 +1,5 @@
27144  #include <sys/types.h>
27145  
27146 -#include <unistd.h>
27147  #include <errno.h>
27148  #include <fcntl.h>
27149  #include <string.h>
27150 @@ -23,6 +22,9 @@
27151  
27152  #include "inet_ntop_cache.h"
27153  #include "crc32.h"
27154 +#include "network.h"
27155 +
27156 +#include "http_resp.h"
27157  
27158  #include <stdio.h>
27159  
27160 @@ -31,6 +33,8 @@
27161  #endif
27162  
27163  #include "sys-socket.h"
27164 +#include "sys-files.h"
27165 +#include "sys-strings.h"
27166  
27167  #define data_proxy data_fastcgi
27168  #define data_proxy_init data_fastcgi_init
27169 @@ -38,22 +42,25 @@
27170  #define PROXY_RETRY_TIMEOUT 60
27171  
27172  /**
27173 - * 
27174 - * the proxy module is based on the fastcgi module 
27175 - * 
27176 + *
27177 + * the proxy module is based on the fastcgi module
27178 + *
27179   * 28.06.2004 Jan Kneschke     The first release
27180   * 01.07.2004 Evgeny Rodichev  Several bugfixes and cleanups
27181   *            - co-ordinate up- and downstream flows correctly (proxy_demux_response
27182   *              and proxy_handle_fdevent)
27183   *            - correctly transfer upstream http_response_status;
27184   *            - some unused structures removed.
27185 - * 
27186 + *
27187   * TODO:      - delay upstream read if write_queue is too large
27188   *              (to prevent memory eating, like in apache). Shoud be
27189   *              configurable).
27190   *            - persistent connection with upstream servers
27191   *            - HTTP/1.1
27192   */
27193 +
27194 +
27195 +
27196  typedef enum {
27197         PROXY_BALANCE_UNSET,
27198         PROXY_BALANCE_FAIR,
27199 @@ -66,26 +73,33 @@
27200         int debug;
27201  
27202         proxy_balance_t balance;
27203 +
27204 +       array *last_used_backends; /* "extension" : last_used_backend */
27205  } plugin_config;
27206  
27207  typedef struct {
27208         PLUGIN_DATA;
27209 -       
27210 +
27211         buffer *parse_response;
27212         buffer *balance_buf;
27213 -       
27214 +
27215 +       http_resp *resp;
27216 +
27217 +       array *ignore_headers;
27218 +
27219         plugin_config **config_storage;
27220 -       
27221 +
27222         plugin_config conf;
27223  } plugin_data;
27224  
27225 -typedef enum { 
27226 -       PROXY_STATE_INIT, 
27227 -       PROXY_STATE_CONNECT, 
27228 -       PROXY_STATE_PREPARE_WRITE, 
27229 -       PROXY_STATE_WRITE, 
27230 -       PROXY_STATE_READ, 
27231 -       PROXY_STATE_ERROR 
27232 +typedef enum {
27233 +       PROXY_STATE_INIT,
27234 +       PROXY_STATE_CONNECT,
27235 +       PROXY_STATE_PREPARE_WRITE,
27236 +       PROXY_STATE_WRITE,
27237 +       PROXY_STATE_RESPONSE_HEADER,
27238 +       PROXY_STATE_RESPONSE_CONTENT,
27239 +       PROXY_STATE_ERROR
27240  } proxy_connection_state_t;
27241  
27242  enum { PROXY_STDOUT, PROXY_END_REQUEST };
27243 @@ -93,19 +107,16 @@
27244  typedef struct {
27245         proxy_connection_state_t state;
27246         time_t state_timestamp;
27247 -       
27248 +
27249         data_proxy *host;
27250 -       
27251 -       buffer *response;
27252 -       buffer *response_header;
27253  
27254         chunkqueue *wb;
27255 -       
27256 -       int fd; /* fd to the proxy process */
27257 -       int fde_ndx; /* index into the fd-event buffer */
27258 +       chunkqueue *rb;
27259 +
27260 +       iosocket *sock; /* fd to the proxy process */
27261  
27262         size_t path_info_offset; /* start of path_info in uri.path */
27263 -       
27264 +
27265         connection *remote_conn;  /* dump pointer */
27266         plugin_data *plugin_data; /* dump pointer */
27267  } handler_ctx;
27268 @@ -116,69 +127,89 @@
27269  
27270  static handler_ctx * handler_ctx_init() {
27271         handler_ctx * hctx;
27272 -       
27273 +
27274  
27275         hctx = calloc(1, sizeof(*hctx));
27276 -       
27277 +
27278         hctx->state = PROXY_STATE_INIT;
27279         hctx->host = NULL;
27280 -       
27281 -       hctx->response = buffer_init();
27282 -       hctx->response_header = buffer_init();
27283  
27284         hctx->wb = chunkqueue_init();
27285 +       hctx->rb = chunkqueue_init();
27286 +
27287 +       hctx->sock = iosocket_init();
27288  
27289 -       hctx->fd = -1;
27290 -       hctx->fde_ndx = -1;
27291 -       
27292         return hctx;
27293  }
27294  
27295  static void handler_ctx_free(handler_ctx *hctx) {
27296 -       buffer_free(hctx->response);
27297 -       buffer_free(hctx->response_header);
27298         chunkqueue_free(hctx->wb);
27299 -       
27300 +       chunkqueue_free(hctx->rb);
27301 +
27302 +       iosocket_free(hctx->sock);
27303 +
27304         free(hctx);
27305  }
27306  
27307  INIT_FUNC(mod_proxy_init) {
27308         plugin_data *p;
27309 -       
27310 +       size_t i;
27311 +
27312 +       char *hop2hop_headers[] = {
27313 +               "Connection",
27314 +               "Keep-Alive",
27315 +               "Host",
27316 +               NULL
27317 +       };
27318 +
27319         p = calloc(1, sizeof(*p));
27320 -       
27321 -       p->parse_response = buffer_init();
27322 +
27323         p->balance_buf = buffer_init();
27324 -       
27325 +       p->ignore_headers = array_init();
27326 +       p->resp = http_response_init();
27327 +
27328 +       for (i = 0; hop2hop_headers[i]; i++) {
27329 +               data_string *ds;
27330 +
27331 +               if (NULL == (ds = (data_string *)array_get_unused_element(p->ignore_headers, TYPE_STRING))) {
27332 +                       ds = data_string_init();
27333 +               }
27334 +
27335 +               buffer_copy_string(ds->key, hop2hop_headers[i]);
27336 +               buffer_copy_string(ds->value, hop2hop_headers[i]);
27337 +               array_insert_unique(p->ignore_headers, (data_unset *)ds);
27338 +       }
27339 +
27340         return p;
27341  }
27342  
27343  
27344  FREE_FUNC(mod_proxy_free) {
27345         plugin_data *p = p_d;
27346 -       
27347 +
27348         UNUSED(srv);
27349  
27350 -       buffer_free(p->parse_response);
27351 -       buffer_free(p->balance_buf);
27352 -       
27353         if (p->config_storage) {
27354                 size_t i;
27355                 for (i = 0; i < srv->config_context->used; i++) {
27356                         plugin_config *s = p->config_storage[i];
27357 -                       
27358 +
27359                         if (s) {
27360 -                       
27361                                 array_free(s->extensions);
27362 -                       
27363 +                               array_free(s->last_used_backends);
27364 +
27365                                 free(s);
27366                         }
27367                 }
27368                 free(p->config_storage);
27369         }
27370 -       
27371 +
27372 +       array_free(p->ignore_headers);
27373 +       buffer_free(p->balance_buf);
27374 +       http_response_free(p->resp);
27375 +
27376         free(p);
27377 -       
27378 +
27379         return HANDLER_GO_ON;
27380  }
27381  
27382 @@ -186,37 +217,38 @@
27383         plugin_data *p = p_d;
27384         data_unset *du;
27385         size_t i = 0;
27386 -       
27387 -       config_values_t cv[] = { 
27388 +
27389 +       config_values_t cv[] = {
27390                 { "proxy.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
27391                 { "proxy.debug",               NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
27392                 { "proxy.balance",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 2 */
27393                 { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
27394         };
27395 -       
27396 +
27397         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
27398 -       
27399 +
27400         for (i = 0; i < srv->config_context->used; i++) {
27401                 plugin_config *s;
27402                 array *ca;
27403 -               
27404 +
27405                 s = malloc(sizeof(plugin_config));
27406 -               s->extensions    = array_init();
27407 +               s->extensions         = array_init();
27408 +               s->last_used_backends = array_init();
27409                 s->debug         = 0;
27410 -               
27411 +
27412                 cv[0].destination = s->extensions;
27413                 cv[1].destination = &(s->debug);
27414                 cv[2].destination = p->balance_buf;
27415  
27416                 buffer_reset(p->balance_buf);
27417 -               
27418 +
27419                 p->config_storage[i] = s;
27420                 ca = ((data_config *)srv->config_context->data[i])->value;
27421 -       
27422 +
27423                 if (0 != config_insert_values_global(srv, ca, cv)) {
27424                         return HANDLER_ERROR;
27425                 }
27426 -       
27427 +
27428                 if (buffer_is_empty(p->balance_buf)) {
27429                         s->balance = PROXY_BALANCE_FAIR;
27430                 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) {
27431 @@ -226,99 +258,99 @@
27432                 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("hash"))) {
27433                         s->balance = PROXY_BALANCE_HASH;
27434                 } else {
27435 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
27436 -                                       "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
27437 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
27438 +                               "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
27439                         return HANDLER_ERROR;
27440                 }
27441  
27442                 if (NULL != (du = array_get_element(ca, "proxy.server"))) {
27443                         size_t j;
27444                         data_array *da = (data_array *)du;
27445 -                       
27446 +
27447                         if (du->type != TYPE_ARRAY) {
27448 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
27449 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
27450                                                 "unexpected type for key: ", "proxy.server", "array of strings");
27451 -                               
27452 +
27453                                 return HANDLER_ERROR;
27454                         }
27455 -                       
27456 -                       /* 
27457 +
27458 +                       /*
27459                          * proxy.server = ( "<ext>" => ...,
27460                          *                  "<ext>" => ... )
27461                          */
27462 -                       
27463 +
27464                         for (j = 0; j < da->value->used; j++) {
27465                                 data_array *da_ext = (data_array *)da->value->data[j];
27466                                 size_t n;
27467 -                               
27468 +
27469                                 if (da_ext->type != TYPE_ARRAY) {
27470 -                                       log_error_write(srv, __FILE__, __LINE__, "sssbs", 
27471 -                                                       "unexpected type for key: ", "proxy.server", 
27472 +                                       log_error_write(srv, __FILE__, __LINE__, "sssbs",
27473 +                                                       "unexpected type for key: ", "proxy.server",
27474                                                         "[", da->value->data[j]->key, "](string)");
27475 -                                       
27476 +
27477                                         return HANDLER_ERROR;
27478                                 }
27479 -                               
27480 -                               /* 
27481 -                                * proxy.server = ( "<ext>" => 
27482 -                                *                     ( "<host>" => ( ... ), 
27483 +
27484 +                               /*
27485 +                                * proxy.server = ( "<ext>" =>
27486 +                                *                     ( "<host>" => ( ... ),
27487                                  *                       "<host>" => ( ... )
27488 -                                *                     ), 
27489 +                                *                     ),
27490                                  *                    "<ext>" => ... )
27491                                  */
27492 -                               
27493 +
27494                                 for (n = 0; n < da_ext->value->used; n++) {
27495                                         data_array *da_host = (data_array *)da_ext->value->data[n];
27496 -                                       
27497 +
27498                                         data_proxy *df;
27499                                         data_array *dfa;
27500 -                                       
27501 -                                       config_values_t pcv[] = { 
27502 +
27503 +                                       config_values_t pcv[] = {
27504                                                 { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 0 */
27505                                                 { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
27506                                                 { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
27507                                         };
27508 -                                       
27509 +
27510                                         if (da_host->type != TYPE_ARRAY) {
27511 -                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS", 
27512 -                                                               "unexpected type for key:", 
27513 -                                                               "proxy.server", 
27514 +                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS",
27515 +                                                               "unexpected type for key:",
27516 +                                                               "proxy.server",
27517                                                                 "[", da_ext->value->data[n]->key, "](string)");
27518 -                                               
27519 +
27520                                                 return HANDLER_ERROR;
27521                                         }
27522 -                                       
27523 +
27524                                         df = data_proxy_init();
27525 -                                       
27526 +
27527                                         df->port = 80;
27528 -                                       
27529 +
27530                                         buffer_copy_string_buffer(df->key, da_host->key);
27531 -                                       
27532 +
27533                                         pcv[0].destination = df->host;
27534                                         pcv[1].destination = &(df->port);
27535 -                                       
27536 +
27537                                         if (0 != config_insert_values_internal(srv, da_host->value, pcv)) {
27538                                                 return HANDLER_ERROR;
27539                                         }
27540 -                                       
27541 +
27542                                         if (buffer_is_empty(df->host)) {
27543 -                                               log_error_write(srv, __FILE__, __LINE__, "sbbbs", 
27544 -                                                               "missing key (string):", 
27545 +                                               log_error_write(srv, __FILE__, __LINE__, "sbbbs",
27546 +                                                               "missing key (string):",
27547                                                                 da->key,
27548                                                                 da_ext->key,
27549                                                                 da_host->key,
27550                                                                 "host");
27551 -                                               
27552 +
27553                                                 return HANDLER_ERROR;
27554                                         }
27555 -                                       
27556 +
27557                                         /* if extension already exists, take it */
27558 -                                       
27559 +
27560                                         if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) {
27561                                                 dfa = data_array_init();
27562 -                                               
27563 +
27564                                                 buffer_copy_string_buffer(dfa->key, da_ext->key);
27565 -                                               
27566 +
27567                                                 array_insert_unique(dfa->value, (data_unset *)df);
27568                                                 array_insert_unique(s->extensions, (data_unset *)dfa);
27569                                         } else {
27570 @@ -328,67 +360,76 @@
27571                         }
27572                 }
27573         }
27574 -       
27575 +
27576         return HANDLER_GO_ON;
27577  }
27578  
27579  void proxy_connection_close(server *srv, handler_ctx *hctx) {
27580         plugin_data *p;
27581         connection *con;
27582 -       
27583 +
27584         if (NULL == hctx) return;
27585 -       
27586 +
27587         p    = hctx->plugin_data;
27588         con  = hctx->remote_conn;
27589 -       
27590 -       if (hctx->fd != -1) {
27591 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
27592 -               fdevent_unregister(srv->ev, hctx->fd);
27593  
27594 -               close(hctx->fd);
27595 +       if (hctx->sock->fd != -1) {
27596 +               fdevent_event_del(srv->ev, hctx->sock);
27597 +               fdevent_unregister(srv->ev, hctx->sock);
27598 +
27599 +               close(hctx->sock->fd);
27600                 srv->cur_fds--;
27601         }
27602 -       
27603 +
27604         handler_ctx_free(hctx);
27605 -       con->plugin_ctx[p->id] = NULL;  
27606 +       con->plugin_ctx[p->id] = NULL;
27607  }
27608  
27609  static int proxy_establish_connection(server *srv, handler_ctx *hctx) {
27610         struct sockaddr *proxy_addr;
27611         struct sockaddr_in proxy_addr_in;
27612         socklen_t servlen;
27613 -       
27614 +
27615         plugin_data *p    = hctx->plugin_data;
27616         data_proxy *host= hctx->host;
27617 -       int proxy_fd       = hctx->fd;
27618 -       
27619 +       int proxy_fd       = hctx->sock->fd;
27620 +
27621         memset(&proxy_addr, 0, sizeof(proxy_addr));
27622 -       
27623 +
27624         proxy_addr_in.sin_family = AF_INET;
27625         proxy_addr_in.sin_addr.s_addr = inet_addr(host->host->ptr);
27626         proxy_addr_in.sin_port = htons(host->port);
27627         servlen = sizeof(proxy_addr_in);
27628 -               
27629 +
27630         proxy_addr = (struct sockaddr *) &proxy_addr_in;
27631 -       
27632 +
27633         if (-1 == connect(proxy_fd, proxy_addr, servlen)) {
27634 -               if (errno == EINPROGRESS || errno == EALREADY) {
27635 +#ifdef _WIN32
27636 +       errno = WSAGetLastError();
27637 +#endif
27638 +       switch(errno) {
27639 +#ifdef _WIN32
27640 +       case WSAEWOULDBLOCK:
27641 +#endif
27642 +       case EINPROGRESS:
27643 +       case EALREADY:
27644                         if (p->conf.debug) {
27645 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
27646 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
27647                                                 "connect delayed:", proxy_fd);
27648                         }
27649 -                       
27650 +
27651                         return 1;
27652 -               } else {
27653 -                       
27654 -                       log_error_write(srv, __FILE__, __LINE__, "sdsd", 
27655 +               default:
27656 +
27657 +                       log_error_write(srv, __FILE__, __LINE__, "sdsd",
27658                                         "connect failed:", proxy_fd, strerror(errno), errno);
27659 -                       
27660 +
27661                         return -1;
27662                 }
27663         }
27664 +       fprintf(stderr, "%s.%d: connected fd = %d\r\n", __FILE__, __LINE__, proxy_fd);
27665         if (p->conf.debug) {
27666 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
27667 +               log_error_write(srv, __FILE__, __LINE__, "sd",
27668                                 "connect succeeded: ", proxy_fd);
27669         }
27670  
27671 @@ -396,51 +437,52 @@
27672  }
27673  
27674  void proxy_set_header(connection *con, const char *key, const char *value) {
27675 -    data_string *ds_dst;
27676 +       data_string *ds_dst;
27677  
27678 -    if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27679 -          ds_dst = data_string_init();
27680 -    }
27681 -
27682 -    buffer_copy_string(ds_dst->key, key);
27683 -    buffer_copy_string(ds_dst->value, value);
27684 -    array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27685 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27686 +               ds_dst = data_string_init();
27687 +       }
27688 +
27689 +       buffer_copy_string(ds_dst->key, key);
27690 +       buffer_copy_string(ds_dst->value, value);
27691 +       array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27692  }
27693  
27694  void proxy_append_header(connection *con, const char *key, const char *value) {
27695 -    data_string *ds_dst;
27696 +       data_string *ds_dst;
27697  
27698 -    if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27699 -          ds_dst = data_string_init();
27700 -    }
27701 -
27702 -    buffer_copy_string(ds_dst->key, key);
27703 -    buffer_append_string(ds_dst->value, value);
27704 -    array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27705 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27706 +               ds_dst = data_string_init();
27707 +       }
27708 +
27709 +       buffer_copy_string(ds_dst->key, key);
27710 +       buffer_append_string(ds_dst->value, value);
27711 +       array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27712  }
27713  
27714  
27715  static int proxy_create_env(server *srv, handler_ctx *hctx) {
27716         size_t i;
27717 -       
27718 +
27719         connection *con   = hctx->remote_conn;
27720 +       plugin_data *p    = hctx->plugin_data;
27721         buffer *b;
27722 -       
27723 +
27724         /* build header */
27725  
27726         b = chunkqueue_get_append_buffer(hctx->wb);
27727 -       
27728 +
27729         /* request line */
27730         buffer_copy_string(b, get_http_method_name(con->request.http_method));
27731         BUFFER_APPEND_STRING_CONST(b, " ");
27732 -       
27733 +
27734         buffer_append_string_buffer(b, con->request.uri);
27735         BUFFER_APPEND_STRING_CONST(b, " HTTP/1.0\r\n");
27736  
27737         proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
27738 -       /* http_host is NOT is just a pointer to a buffer 
27739 +       /* http_host is NOT is just a pointer to a buffer
27740          * which is NULL if it is not set */
27741 -       if (con->request.http_host && 
27742 +       if (con->request.http_host &&
27743             !buffer_is_empty(con->request.http_host)) {
27744                 proxy_set_header(con, "X-Host", con->request.http_host->ptr);
27745         }
27746 @@ -449,24 +491,25 @@
27747         /* request header */
27748         for (i = 0; i < con->request.headers->used; i++) {
27749                 data_string *ds;
27750 -               
27751 +
27752                 ds = (data_string *)con->request.headers->data[i];
27753 -               
27754 -               if (ds->value->used && ds->key->used) {
27755 -                       if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
27756 -                       
27757 -                       buffer_append_string_buffer(b, ds->key);
27758 -                       BUFFER_APPEND_STRING_CONST(b, ": ");
27759 -                       buffer_append_string_buffer(b, ds->value);
27760 -                       BUFFER_APPEND_STRING_CONST(b, "\r\n");
27761 -               }
27762 +
27763 +               if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
27764 +
27765 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
27766 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
27767 +
27768 +               buffer_append_string_buffer(b, ds->key);
27769 +               BUFFER_APPEND_STRING_CONST(b, ": ");
27770 +               buffer_append_string_buffer(b, ds->value);
27771 +               BUFFER_APPEND_STRING_CONST(b, "\r\n");
27772         }
27773 -       
27774 +
27775         BUFFER_APPEND_STRING_CONST(b, "\r\n");
27776 -       
27777 +
27778         hctx->wb->bytes_in += b->used - 1;
27779         /* body */
27780 -       
27781 +
27782         if (con->request.content_length) {
27783                 chunkqueue *req_cq = con->request_content_queue;
27784                 chunk *req_c;
27785 @@ -479,7 +522,7 @@
27786  
27787                         /* we announce toWrite octects
27788                          * now take all the request_content chunk that we need to fill this request
27789 -                        * */   
27790 +                        * */
27791  
27792                         switch (req_c->type) {
27793                         case FILE_CHUNK:
27794 @@ -507,223 +550,150 @@
27795  
27796                                 req_c->offset += weHave;
27797                                 req_cq->bytes_out += weHave;
27798 -                               
27799 +
27800                                 hctx->wb->bytes_in += weHave;
27801  
27802                                 break;
27803                         default:
27804                                 break;
27805                         }
27806 -                       
27807 +
27808                         offset += weHave;
27809                 }
27810  
27811         }
27812 -       
27813 +
27814         return 0;
27815  }
27816  
27817  static int proxy_set_state(server *srv, handler_ctx *hctx, proxy_connection_state_t state) {
27818         hctx->state = state;
27819         hctx->state_timestamp = srv->cur_ts;
27820 -       
27821 -       return 0;
27822 -}
27823  
27824 -
27825 -static int proxy_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
27826 -       char *s, *ns;
27827 -       int http_response_status = -1;
27828 -       
27829 -       UNUSED(srv);
27830 -
27831 -       /* \r\n -> \0\0 */
27832 -       
27833 -       buffer_copy_string_buffer(p->parse_response, in);
27834 -       
27835 -       for (s = p->parse_response->ptr; NULL != (ns = strstr(s, "\r\n")); s = ns + 2) {
27836 -               char *key, *value;
27837 -               int key_len;
27838 -               data_string *ds;
27839 -               int copy_header;
27840 -               
27841 -               ns[0] = '\0';
27842 -               ns[1] = '\0';
27843 -
27844 -               if (-1 == http_response_status) {
27845 -                       /* The first line of a Response message is the Status-Line */
27846 -
27847 -                       for (key=s; *key && *key != ' '; key++);
27848 -
27849 -                       if (*key) {
27850 -                               http_response_status = (int) strtol(key, NULL, 10);
27851 -                               if (http_response_status <= 0) http_response_status = 502;
27852 -                       } else {
27853 -                               http_response_status = 502;
27854 -                       }
27855 -
27856 -                       con->http_status = http_response_status;
27857 -                       con->parsed_response |= HTTP_STATUS;
27858 -                       continue;
27859 -               }
27860 -               
27861 -               if (NULL == (value = strchr(s, ':'))) {
27862 -                       /* now we expect: "<key>: <value>\n" */
27863 -
27864 -                       continue;
27865 -               }
27866 -
27867 -               key = s;
27868 -               key_len = value - key;
27869 -               
27870 -               value++;
27871 -               /* strip WS */
27872 -               while (*value == ' ' || *value == '\t') value++;
27873 -               
27874 -               copy_header = 1;
27875 -               
27876 -               switch(key_len) {
27877 -               case 4:
27878 -                       if (0 == strncasecmp(key, "Date", key_len)) {
27879 -                               con->parsed_response |= HTTP_DATE;
27880 -                       }
27881 -                       break;
27882 -               case 8:
27883 -                       if (0 == strncasecmp(key, "Location", key_len)) {
27884 -                               con->parsed_response |= HTTP_LOCATION;
27885 -                       }
27886 -                       break;
27887 -               case 10:
27888 -                       if (0 == strncasecmp(key, "Connection", key_len)) {
27889 -                               copy_header = 0;
27890 -                       }
27891 -                       break;
27892 -               case 14:
27893 -                       if (0 == strncasecmp(key, "Content-Length", key_len)) {
27894 -                               con->response.content_length = strtol(value, NULL, 10);
27895 -                               con->parsed_response |= HTTP_CONTENT_LENGTH;
27896 -                       }
27897 -                       break;
27898 -               default:
27899 -                       break;
27900 -               }
27901 -
27902 -               if (copy_header) {
27903 -                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
27904 -                               ds = data_response_init();
27905 -                       }
27906 -                       buffer_copy_string_len(ds->key, key, key_len);
27907 -                       buffer_copy_string(ds->value, value);
27908 -                       
27909 -                       array_insert_unique(con->response.headers, (data_unset *)ds);
27910 -               }
27911 -       }
27912 -       
27913         return 0;
27914  }
27915  
27916  
27917  static int proxy_demux_response(server *srv, handler_ctx *hctx) {
27918 -       int fin = 0;
27919 -       int b;
27920 -       ssize_t r;
27921 -       
27922         plugin_data *p    = hctx->plugin_data;
27923         connection *con   = hctx->remote_conn;
27924 -       int proxy_fd       = hctx->fd;
27925 -       
27926 -       /* check how much we have to read */
27927 -       if (ioctl(hctx->fd, FIONREAD, &b)) {
27928 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
27929 -                               "ioctl failed: ",
27930 -                               proxy_fd);
27931 +       chunkqueue *next_queue = NULL;
27932 +       chunk *c = NULL;
27933 +
27934 +       switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
27935 +       case NETWORK_STATUS_SUCCESS:
27936 +               /* we got content */
27937 +               break;
27938 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
27939 +               return 0;
27940 +       case NETWORK_STATUS_CONNECTION_CLOSE:
27941 +               /* we are done, get out of here */
27942 +               con->file_finished = 1;
27943 +
27944 +               /* close the chunk-queue with a empty chunk */
27945 +
27946 +               return 1;
27947 +       default:
27948 +               /* oops */
27949                 return -1;
27950         }
27951  
27952 +       /* looks like we got some content
27953 +       *
27954 +       * split off the header from the incoming stream
27955 +       */
27956  
27957 -       if (p->conf.debug) {
27958 -               log_error_write(srv, __FILE__, __LINE__, "sd",
27959 -                              "proxy - have to read:", b);
27960 -       }
27961 +       if (hctx->state == PROXY_STATE_RESPONSE_HEADER) {
27962 +               size_t i;
27963 +               int have_content_length = 0;
27964  
27965 -       if (b > 0) {
27966 -               if (hctx->response->used == 0) {
27967 -                       /* avoid too small buffer */
27968 -                       buffer_prepare_append(hctx->response, b + 1);
27969 -                       hctx->response->used = 1;
27970 -               } else {
27971 -                       buffer_prepare_append(hctx->response, hctx->response->used + b);
27972 -               }
27973 -               
27974 -               if (-1 == (r = read(hctx->fd, hctx->response->ptr + hctx->response->used - 1, b))) {
27975 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
27976 -                                       "unexpected end-of-file (perhaps the proxy process died):",
27977 -                                       proxy_fd, strerror(errno));
27978 -                       return -1;
27979 -               }
27980 -               
27981 -               /* this should be catched by the b > 0 above */
27982 -               assert(r);
27983 -               
27984 -               hctx->response->used += r;
27985 -               hctx->response->ptr[hctx->response->used - 1] = '\0';
27986 -
27987 -#if 0
27988 -               log_error_write(srv, __FILE__, __LINE__, "sdsbs", 
27989 -                               "demux: Response buffer len", hctx->response->used, ":", hctx->response, ":");
27990 -#endif
27991 +               http_response_reset(p->resp);
27992  
27993 -               if (0 == con->got_response) {
27994 -                       con->got_response = 1;
27995 -                       buffer_prepare_copy(hctx->response_header, 128);
27996 -               }
27997 -                               
27998 -               if (0 == con->file_started) {
27999 -                       char *c;
28000 -                               
28001 -                       /* search for the \r\n\r\n in the string */
28002 -                       if (NULL != (c = buffer_search_string_len(hctx->response, "\r\n\r\n", 4))) {
28003 -                               size_t hlen = c - hctx->response->ptr + 4;
28004 -                               size_t blen = hctx->response->used - hlen - 1;
28005 -                               /* found */
28006 -                               
28007 -                               buffer_append_string_len(hctx->response_header, hctx->response->ptr, c - hctx->response->ptr + 4);
28008 -#if 0
28009 -                               log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header);
28010 -#endif
28011 -                               /* parse the response header */
28012 -                               proxy_response_parse(srv, con, p, hctx->response_header);
28013 -                                       
28014 -                               /* enable chunked-transfer-encoding */
28015 -                               if (con->request.http_version == HTTP_VERSION_1_1 &&
28016 -                                   !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
28017 -                                       con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
28018 +               /* the response header is not fully received yet,
28019 +               *
28020 +               * extract the http-response header from the rb-cq
28021 +               */
28022 +               switch (http_response_parse_cq(hctx->rb, p->resp)) {
28023 +               case PARSE_ERROR:
28024 +                       /* parsing failed */
28025 +
28026 +                       con->http_status = 502; /* Bad Gateway */
28027 +                       return 1;
28028 +               case PARSE_NEED_MORE:
28029 +                       return 0;
28030 +               case PARSE_SUCCESS:
28031 +                       con->http_status = p->resp->status;
28032 +
28033 +                       chunkqueue_remove_finished_chunks(hctx->rb);
28034 +
28035 +                       /* copy the http-headers */
28036 +                       for (i = 0; i < p->resp->headers->used; i++) {
28037 +                               const char *ign[] = { "Status", "Connection", NULL };
28038 +                               size_t j;
28039 +                               data_string *ds;
28040 +
28041 +                               data_string *header = (data_string *)p->resp->headers->data[i];
28042 +
28043 +                               /* some headers are ignored by default */
28044 +                               for (j = 0; ign[j]; j++) {
28045 +                                       if (0 == strcasecmp(ign[j], header->key->ptr)) break;
28046 +                               }
28047 +                               if (ign[j]) continue;
28048 +
28049 +                               if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
28050 +                                       /* CGI/1.1 rev 03 - 7.2.1.2 */
28051 +                                       if (con->http_status == 0) con->http_status = 302;
28052 +                               } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
28053 +                                       have_content_length = 1;
28054                                 }
28055 -                                       
28056 -                               con->file_started = 1;
28057 -                               if (blen) {
28058 -                                       http_chunk_append_mem(srv, con, c + 4, blen + 1);
28059 -                                       joblist_append(srv, con);
28060 +                               
28061 +                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
28062 +                                       ds = data_response_init();
28063                                 }
28064 -                               hctx->response->used = 0;
28065 +                               buffer_copy_string_buffer(ds->key, header->key);
28066 +                               buffer_copy_string_buffer(ds->value, header->value);
28067 +
28068 +                               array_insert_unique(con->response.headers, (data_unset *)ds);
28069                         }
28070 -               } else {
28071 -                       http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
28072 -                       joblist_append(srv, con);
28073 -                       hctx->response->used = 0;
28074 +
28075 +                       con->file_started = 1;
28076 +
28077 +                       if (con->request.http_version == HTTP_VERSION_1_1 &&
28078 +                           !have_content_length) {
28079 +                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
28080 +                       }
28081 +
28082 +                       hctx->state = PROXY_STATE_RESPONSE_CONTENT;
28083 +                       break;
28084                 }
28085 -               
28086 -       } else {
28087 -               /* reading from upstream done */
28088 -               con->file_finished = 1;
28089 -               
28090 -               http_chunk_append_mem(srv, con, NULL, 0);
28091 -               joblist_append(srv, con);
28092 -               
28093 -               fin = 1;
28094         }
28095 -       
28096 -       return fin;
28097 +
28098 +       /* FIXME: pass the response-header to the other plugins to
28099 +       * setup the filter-queue
28100 +       *
28101 +       * - use next-queue instead of con->write_queue
28102 +       */
28103 +
28104 +       next_queue = con->write_queue;
28105 +
28106 +       assert(hctx->state == PROXY_STATE_RESPONSE_CONTENT);
28107 +
28108 +       /* FIXME: if we have a content-length or chunked-encoding
28109 +       * handle it.
28110 +       *
28111 +       * for now we wait for EOF on the socket */
28112 +
28113 +       /* copy the content to the next cq */
28114 +       for (c = hctx->rb->first; c; c = c->next) {
28115 +               http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
28116 +
28117 +               c->offset = c->mem->used - 1;
28118 +       }
28119 +
28120 +       chunkqueue_remove_finished_chunks(hctx->rb);
28121 +       joblist_append(srv, con);
28122 +
28123 +       return 0;
28124  }
28125  
28126  
28127 @@ -731,32 +701,32 @@
28128         data_proxy *host= hctx->host;
28129         plugin_data *p    = hctx->plugin_data;
28130         connection *con   = hctx->remote_conn;
28131 -       
28132 +
28133         int ret;
28134 -       
28135 -       if (!host || 
28136 -           (!host->host->used || !host->port)) return -1;
28137 -       
28138 +
28139 +       if (!host ||
28140 +               (!host->host->used || !host->port)) return -1;
28141 +
28142         switch(hctx->state) {
28143         case PROXY_STATE_INIT:
28144 -               if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
28145 +               if (-1 == (hctx->sock->fd = socket(AF_INET, SOCK_STREAM, 0))) {
28146                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
28147                         return HANDLER_ERROR;
28148                 }
28149 -               hctx->fde_ndx = -1;
28150 -               
28151 +               hctx->sock->fde_ndx = -1;
28152 +
28153                 srv->cur_fds++;
28154 -               
28155 -               fdevent_register(srv->ev, hctx->fd, proxy_handle_fdevent, hctx);
28156 -               
28157 -               if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
28158 +
28159 +               fdevent_register(srv->ev, hctx->sock, proxy_handle_fdevent, hctx);
28160 +
28161 +               if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
28162                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
28163 -                       
28164 +
28165                         return HANDLER_ERROR;
28166                 }
28167 -               
28168 +
28169                 /* fall through */
28170 -               
28171 +
28172         case PROXY_STATE_CONNECT:
28173                 /* try to finish the connect() */
28174                 if (hctx->state == PROXY_STATE_INIT) {
28175 @@ -764,16 +734,16 @@
28176                         switch (proxy_establish_connection(srv, hctx)) {
28177                         case 1:
28178                                 proxy_set_state(srv, hctx, PROXY_STATE_CONNECT);
28179 -                               
28180 +
28181                                 /* connection is in progress, wait for an event and call getsockopt() below */
28182 -                               
28183 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28184 -                               
28185 +
28186 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
28187 +
28188                                 return HANDLER_WAIT_FOR_EVENT;
28189                         case -1:
28190                                 /* if ECONNREFUSED choose another connection -> FIXME */
28191 -                               hctx->fde_ndx = -1;
28192 -                               
28193 +                               hctx->sock->fde_ndx = -1;
28194 +
28195                                 return HANDLER_ERROR;
28196                         default:
28197                                 /* everything is ok, go on */
28198 @@ -782,152 +752,152 @@
28199                 } else {
28200                         int socket_error;
28201                         socklen_t socket_error_len = sizeof(socket_error);
28202 -               
28203 -                       /* we don't need it anymore */  
28204 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
28205 +
28206 +                       /* we don't need it anymore */
28207 +                       fdevent_event_del(srv->ev, hctx->sock);
28208  
28209                         /* try to finish the connect() */
28210 -                       if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28211 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
28212 +                       if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28213 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
28214                                                 "getsockopt failed:", strerror(errno));
28215 -                               
28216 +
28217                                 return HANDLER_ERROR;
28218                         }
28219                         if (socket_error != 0) {
28220                                 log_error_write(srv, __FILE__, __LINE__, "ss",
28221 -                                               "establishing connection failed:", strerror(socket_error), 
28222 +                                               "establishing connection failed:", strerror(socket_error),
28223                                                 "port:", hctx->host->port);
28224 -                               
28225 +
28226                                 return HANDLER_ERROR;
28227                         }
28228                         if (p->conf.debug) {
28229 -                               log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - connect - delayed success"); 
28230 +                               log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - connect - delayed success");
28231                         }
28232                 }
28233 -               
28234 +
28235                 proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);
28236                 /* fall through */
28237         case PROXY_STATE_PREPARE_WRITE:
28238                 proxy_create_env(srv, hctx);
28239 -               
28240 +
28241                 proxy_set_state(srv, hctx, PROXY_STATE_WRITE);
28242 -               
28243 +
28244                 /* fall through */
28245         case PROXY_STATE_WRITE:;
28246 -               ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); 
28247 +               ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
28248  
28249                 chunkqueue_remove_finished_chunks(hctx->wb);
28250  
28251 -               if (-1 == ret) {
28252 -                       if (errno != EAGAIN &&
28253 -                           errno != EINTR) {
28254 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
28255 -                               
28256 -                               return HANDLER_ERROR;
28257 -                       } else {
28258 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28259 +               switch(ret) {
28260 +               case NETWORK_STATUS_FATAL_ERROR:
28261 +                       log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
28262  
28263 -                               return HANDLER_WAIT_FOR_EVENT;
28264 -                       }
28265 +                       return HANDLER_ERROR;
28266 +               case NETWORK_STATUS_WAIT_FOR_EVENT:
28267 +
28268 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
28269 +
28270 +                       return HANDLER_WAIT_FOR_EVENT;
28271                 }
28272  
28273                 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
28274 -                       proxy_set_state(srv, hctx, PROXY_STATE_READ);
28275 +                       proxy_set_state(srv, hctx, PROXY_STATE_RESPONSE_HEADER);
28276  
28277 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
28278 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
28279 +                       fdevent_event_del(srv->ev, hctx->sock);
28280 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
28281                 } else {
28282 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28283 -                               
28284 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
28285 +
28286                         return HANDLER_WAIT_FOR_EVENT;
28287                 }
28288 -               
28289 +
28290                 return HANDLER_WAIT_FOR_EVENT;
28291 -       case PROXY_STATE_READ:
28292 +       case PROXY_STATE_RESPONSE_CONTENT:
28293 +       case PROXY_STATE_RESPONSE_HEADER:
28294                 /* waiting for a response */
28295 +
28296                 return HANDLER_WAIT_FOR_EVENT;
28297         default:
28298                 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
28299                 return HANDLER_ERROR;
28300         }
28301 -       
28302 +
28303         return HANDLER_GO_ON;
28304  }
28305  
28306 -#define PATCH(x) \
28307 -       p->conf.x = s->x;
28308  static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data *p) {
28309         size_t i, j;
28310         plugin_config *s = p->config_storage[0];
28311 -       
28312 -       PATCH(extensions);
28313 -       PATCH(debug);
28314 -       PATCH(balance);
28315 -       
28316 +
28317 +       PATCH_OPTION(extensions);
28318 +       PATCH_OPTION(debug);
28319 +       PATCH_OPTION(balance);
28320 +       PATCH_OPTION(last_used_backends);
28321 +
28322         /* skip the first, the global context */
28323         for (i = 1; i < srv->config_context->used; i++) {
28324                 data_config *dc = (data_config *)srv->config_context->data[i];
28325                 s = p->config_storage[i];
28326 -               
28327 +
28328                 /* condition didn't match */
28329                 if (!config_check_cond(srv, con, dc)) continue;
28330 -               
28331 +
28332                 /* merge config */
28333                 for (j = 0; j < dc->value->used; j++) {
28334                         data_unset *du = dc->value->data[j];
28335 -                       
28336 +
28337                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.server"))) {
28338 -                               PATCH(extensions);
28339 +                               PATCH_OPTION(extensions);
28340                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.debug"))) {
28341 -                               PATCH(debug);
28342 +                               PATCH_OPTION(debug);
28343                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.balance"))) {
28344 -                               PATCH(balance);
28345 +                               PATCH_OPTION(balance);
28346 +                               PATCH_OPTION(last_used_backends);
28347                         }
28348                 }
28349         }
28350 -       
28351 +
28352         return 0;
28353  }
28354 -#undef PATCH
28355  
28356  SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
28357         plugin_data *p = p_d;
28358 -       
28359 +
28360         handler_ctx *hctx = con->plugin_ctx[p->id];
28361         data_proxy *host;
28362 -       
28363 +
28364         if (NULL == hctx) return HANDLER_GO_ON;
28365  
28366         mod_proxy_patch_connection(srv, con, p);
28367 -       
28368 +
28369         host = hctx->host;
28370 -       
28371 +
28372         /* not my job */
28373         if (con->mode != p->id) return HANDLER_GO_ON;
28374 -       
28375 +
28376         /* ok, create the request */
28377         switch(proxy_write_request(srv, hctx)) {
28378         case HANDLER_ERROR:
28379 -               log_error_write(srv, __FILE__, __LINE__,  "sbdd", "proxy-server disabled:", 
28380 +               log_error_write(srv, __FILE__, __LINE__,  "sbdd", "proxy-server disabled:",
28381                                 host->host,
28382                                 host->port,
28383 -                               hctx->fd);
28384 -               
28385 +                               hctx->sock->fd);
28386 +
28387                 /* disable this server */
28388                 host->is_disabled = 1;
28389                 host->disable_ts = srv->cur_ts;
28390 -               
28391 +
28392                 proxy_connection_close(srv, hctx);
28393 -       
28394 -               /* reset the enviroment and restart the sub-request */  
28395 +
28396 +               /* reset the enviroment and restart the sub-request */
28397                 buffer_reset(con->physical.path);
28398                 con->mode = DIRECT;
28399  
28400                 joblist_append(srv, con);
28401  
28402 -               /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop 
28403 -                * and hope that the childs will be restarted 
28404 -                * 
28405 +               /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
28406 +                * and hope that the childs will be restarted
28407 +                *
28408                  */
28409  
28410                 return HANDLER_WAIT_FOR_FD;
28411 @@ -938,7 +908,7 @@
28412         default:
28413                 break;
28414         }
28415 -       
28416 +
28417         if (con->file_started == 1) {
28418                 return HANDLER_FINISHED;
28419         } else {
28420 @@ -951,13 +921,14 @@
28421         handler_ctx *hctx = ctx;
28422         connection  *con  = hctx->remote_conn;
28423         plugin_data *p    = hctx->plugin_data;
28424 -       
28425 -       
28426 +
28427 +
28428         if ((revents & FDEVENT_IN) &&
28429 -           hctx->state == PROXY_STATE_READ) {
28430 +           (hctx->state == PROXY_STATE_RESPONSE_HEADER ||
28431 +            hctx->state == PROXY_STATE_RESPONSE_CONTENT)) {
28432  
28433                 if (p->conf.debug) {
28434 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28435 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28436                                         "proxy: fdevent-in", hctx->state);
28437                 }
28438  
28439 @@ -965,11 +936,15 @@
28440                 case 0:
28441                         break;
28442                 case 1:
28443 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28444 +                                       "proxy: request done", hctx->sock->fd);
28445                         hctx->host->usage--;
28446 -                       
28447 +
28448 +                       http_chunk_append_mem(srv, con, NULL, 0);
28449 +
28450                         /* we are done */
28451                         proxy_connection_close(srv, hctx);
28452 -                       
28453 +
28454                         joblist_append(srv, con);
28455                         return HANDLER_FINISHED;
28456                 case -1:
28457 @@ -982,53 +957,53 @@
28458                                 /* response might have been already started, kill the connection */
28459                                 connection_set_state(srv, con, CON_STATE_ERROR);
28460                         }
28461 -                       
28462 +
28463                         joblist_append(srv, con);
28464                         return HANDLER_FINISHED;
28465                 }
28466         }
28467 -       
28468 +
28469         if (revents & FDEVENT_OUT) {
28470                 if (p->conf.debug) {
28471 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28472 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28473                                         "proxy: fdevent-out", hctx->state);
28474                 }
28475  
28476                 if (hctx->state == PROXY_STATE_CONNECT ||
28477                     hctx->state == PROXY_STATE_WRITE) {
28478                         /* we are allowed to send something out
28479 -                        * 
28480 +                        *
28481                          * 1. in a unfinished connect() call
28482                          * 2. in a unfinished write() call (long POST request)
28483                          */
28484                         return mod_proxy_handle_subrequest(srv, con, p);
28485                 } else {
28486 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28487 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28488                                         "proxy: out", hctx->state);
28489                 }
28490         }
28491 -       
28492 +
28493         /* perhaps this issue is already handled */
28494         if (revents & FDEVENT_HUP) {
28495                 if (p->conf.debug) {
28496 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28497 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28498                                         "proxy: fdevent-hup", hctx->state);
28499                 }
28500 -               
28501 +
28502                 if (hctx->state == PROXY_STATE_CONNECT) {
28503                         /* connect() -> EINPROGRESS -> HUP */
28504 -                       
28505 +
28506                         /**
28507 -                        * what is proxy is doing if it can't reach the next hop ? 
28508 -                        * 
28509 +                        * what is proxy is doing if it can't reach the next hop ?
28510 +                        *
28511                          */
28512 -                       
28513 +
28514                         proxy_connection_close(srv, hctx);
28515                         joblist_append(srv, con);
28516 -                       
28517 +
28518                         con->http_status = 503;
28519                         con->mode = DIRECT;
28520 -                       
28521 +
28522                         return HANDLER_FINISHED;
28523                 }
28524  
28525 @@ -1038,13 +1013,13 @@
28526                 joblist_append(srv, con);
28527         } else if (revents & FDEVENT_ERR) {
28528                 /* kill all connections to the proxy process */
28529 -               
28530 +
28531                 log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents);
28532  
28533                 joblist_append(srv, con);
28534                 proxy_connection_close(srv, hctx);
28535         }
28536 -       
28537 +
28538         return HANDLER_FINISHED;
28539  }
28540  
28541 @@ -1058,44 +1033,48 @@
28542         buffer *fn;
28543         data_array *extension = NULL;
28544         size_t path_info_offset;
28545 -       
28546 +       data_integer *last_used_backend;
28547 +       data_proxy *host = NULL;
28548 +       handler_ctx *hctx = NULL;
28549 +
28550 +       array *backends = NULL;
28551 +
28552         /* Possibly, we processed already this request */
28553         if (con->file_started == 1) return HANDLER_GO_ON;
28554 -       
28555 +
28556         mod_proxy_patch_connection(srv, con, p);
28557 -       
28558 +
28559         fn = con->uri.path;
28560  
28561         if (fn->used == 0) {
28562                 return HANDLER_ERROR;
28563         }
28564 -       
28565 +
28566         s_len = fn->used - 1;
28567 -       
28568 -       
28569 +
28570         path_info_offset = 0;
28571  
28572 -       if (p->conf.debug) {    
28573 +       if (p->conf.debug) {
28574                 log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - start");
28575         }
28576  
28577         /* check if extension matches */
28578         for (k = 0; k < p->conf.extensions->used; k++) {
28579                 size_t ct_len;
28580 -               
28581 +
28582                 extension = (data_array *)p->conf.extensions->data[k];
28583 -               
28584 +
28585                 if (extension->key->used == 0) continue;
28586 -               
28587 +
28588                 ct_len = extension->key->used - 1;
28589 -               
28590 +
28591                 if (s_len < ct_len) continue;
28592 -               
28593 +
28594                 /* check extension in the form "/proxy_pattern" */
28595                 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
28596                         if (s_len > ct_len + 1) {
28597                                 char *pi_offset;
28598 -                               
28599 +
28600                                 if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) {
28601                                         path_info_offset = pi_offset - fn->ptr;
28602                                 }
28603 @@ -1106,12 +1085,14 @@
28604                         break;
28605                 }
28606         }
28607 -       
28608 +
28609         if (k == p->conf.extensions->used) {
28610                 return HANDLER_GO_ON;
28611         }
28612  
28613 -       if (p->conf.debug) {    
28614 +       backends = extension->value;
28615 +
28616 +       if (p->conf.debug) {
28617                 log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - ext found");
28618         }
28619  
28620 @@ -1120,34 +1101,34 @@
28621                 /* hash balancing */
28622  
28623                 if (p->conf.debug) {
28624 -                       log_error_write(srv, __FILE__, __LINE__,  "sd", 
28625 -                                       "proxy - used hash balancing, hosts:", extension->value->used);
28626 +                       log_error_write(srv, __FILE__, __LINE__,  "sd",
28627 +                                       "proxy - used hash balancing, hosts:", backends->used);
28628                 }
28629  
28630 -               for (k = 0, ndx = -1, last_max = ULONG_MAX; k < extension->value->used; k++) {
28631 -                       data_proxy *host = (data_proxy *)extension->value->data[k];
28632 +               for (k = 0, ndx = -1, last_max = ULONG_MAX; k < backends->used; k++) {
28633                         unsigned long cur_max;
28634  
28635 -                       if (host->is_disabled) continue;
28636 -                       
28637 +                       data_proxy *cur = (data_proxy *)backends->data[k];
28638 +
28639 +                       if (cur->is_disabled) continue;
28640 +
28641                         cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
28642 -                               generate_crc32c(CONST_BUF_LEN(host->host)) + /* we can cache this */
28643 +                               generate_crc32c(CONST_BUF_LEN(cur->host)) + /* we can cache this */
28644                                 generate_crc32c(CONST_BUF_LEN(con->uri.authority));
28645 -                       
28646 +
28647                         if (p->conf.debug) {
28648 -                               log_error_write(srv, __FILE__, __LINE__,  "sbbbd", 
28649 +                               log_error_write(srv, __FILE__, __LINE__,  "sbbbd",
28650                                                 "proxy - election:",
28651                                                 con->uri.path,
28652 -                                               host->host,
28653 +                                               cur->host,
28654                                                 con->uri.authority,
28655                                                 cur_max);
28656                         }
28657  
28658 -                       if ((last_max == ULONG_MAX) || /* first round */
28659 -                           (cur_max > last_max)) {
28660 +                       if (host == NULL || (cur_max > last_max)) {
28661                                 last_max = cur_max;
28662  
28663 -                               ndx = k;
28664 +                               host = cur;
28665                         }
28666                 }
28667  
28668 @@ -1155,19 +1136,20 @@
28669         case PROXY_BALANCE_FAIR:
28670                 /* fair balancing */
28671                 if (p->conf.debug) {
28672 -                       log_error_write(srv, __FILE__, __LINE__,  "s", 
28673 +                       log_error_write(srv, __FILE__, __LINE__,  "s",
28674                                         "proxy - used fair balancing");
28675                 }
28676  
28677 -               for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
28678 -                       data_proxy *host = (data_proxy *)extension->value->data[k];
28679 -               
28680 -                       if (host->is_disabled) continue;
28681 -
28682 -                       if (host->usage < max_usage) {
28683 -                               max_usage = host->usage;
28684 -                       
28685 -                               ndx = k;
28686 +               /* try to find the host with the lowest load */
28687 +               for (k = 0, max_usage = 0; k < backends->used; k++) {
28688 +                       data_proxy *cur = (data_proxy *)backends->data[k];
28689 +
28690 +                       if (cur->is_disabled) continue;
28691 +
28692 +                       if (NULL == host || cur->usage < max_usage) {
28693 +                               max_usage = cur->usage;
28694 +
28695 +                               host = cur;
28696                         }
28697                 }
28698  
28699 @@ -1175,89 +1157,100 @@
28700         case PROXY_BALANCE_RR:
28701                 /* round robin */
28702                 if (p->conf.debug) {
28703 -                       log_error_write(srv, __FILE__, __LINE__,  "s", 
28704 +                       log_error_write(srv, __FILE__, __LINE__,  "s",
28705                                         "proxy - used round-robin balancing");
28706                 }
28707  
28708                 /* just to be sure */
28709 -               assert(extension->value->used < INT_MAX);
28710 -               
28711 -               for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
28712 -                       data_proxy *host = (data_proxy *)extension->value->data[k];
28713 -               
28714 -                       if (host->is_disabled) continue;
28715 -
28716 -                       /* first usable ndx */
28717 -                       if (max_usage == INT_MAX) {
28718 -                               max_usage = k;
28719 -                       }
28720 +               assert(backends->used < INT_MAX);
28721  
28722 -                       /* get next ndx */
28723 -                       if ((int)k > host->last_used_ndx) {
28724 -                               ndx = k;
28725 -                               host->last_used_ndx = k;
28726 +               /* send each request to another host:
28727 +                *
28728 +                * e.g.:
28729 +                *
28730 +                * if we have three hosts it is
28731 +                *
28732 +                * 1 .. 2 .. 3 .. 1 .. 2 .. 3
28733 +                *
28734 +                **/
28735  
28736 -                               break;
28737 -                       }
28738 +               /* walk through the list */
28739 +               last_used_backend = (data_integer *)array_get_element(p->conf.last_used_backends, extension->key->ptr);
28740 +
28741 +               if (NULL == last_used_backend) {
28742 +                       last_used_backend = data_integer_init();
28743 +
28744 +                       buffer_copy_string_buffer(last_used_backend->key, extension->key);
28745 +                       last_used_backend->value = 0;
28746 +
28747 +                       array_insert_unique(p->conf.last_used_backends, (data_unset *)last_used_backend);
28748 +               }
28749 +
28750 +               /* scan all but the last host to see if they are up
28751 +                * take the first running host */
28752 +               for (k = last_used_backend->value + 1; (int)(k % backends->used) != last_used_backend->value; k++) {
28753 +                       data_proxy *cur = (data_proxy *)backends->data[k % backends->used];
28754 +
28755 +                       if (cur->is_disabled) continue;
28756 +
28757 +                       host = cur;
28758 +
28759 +                       last_used_backend->value = k;
28760 +
28761 +                       break;
28762                 }
28763 -               
28764 -               /* didn't found a higher id, wrap to the start */
28765 -               if (ndx != -1 && max_usage != INT_MAX) {
28766 -                       ndx = max_usage;
28767 +
28768 +               if (NULL == host) {
28769 +                       /* we found nothing better, fallback to the last used backend
28770 +                        * and check if it is still up */
28771 +                       host = (data_proxy *)backends->data[last_used_backend->value];
28772 +
28773 +                       if (host->is_disabled) host = NULL;
28774                 }
28775  
28776                 break;
28777         default:
28778                 break;
28779         }
28780 -       
28781 -       /* found a server */
28782 -       if (ndx != -1) {
28783 -               data_proxy *host = (data_proxy *)extension->value->data[ndx];
28784 -               
28785 -               /* 
28786 -                * if check-local is disabled, use the uri.path handler 
28787 -                * 
28788 -                */
28789 -               
28790 -               /* init handler-context */
28791 -               handler_ctx *hctx;
28792 -               hctx = handler_ctx_init();
28793 -                               
28794 -               hctx->path_info_offset = path_info_offset;
28795 -               hctx->remote_conn      = con;
28796 -               hctx->plugin_data      = p;
28797 -               hctx->host             = host;
28798 -                               
28799 -               con->plugin_ctx[p->id] = hctx;
28800 -               
28801 -               host->usage++;
28802 -               
28803 -               con->mode = p->id;
28804 -               
28805 -               if (p->conf.debug) {
28806 -                       log_error_write(srv, __FILE__, __LINE__,  "sbd", 
28807 -                                       "proxy - found a host",
28808 -                                       host->host, host->port);
28809 -               }
28810  
28811 -               return HANDLER_GO_ON;
28812 -       } else {
28813 -               /* no handler found */
28814 +       /* we havn't found a host */
28815 +       if (NULL == host) {
28816                 con->http_status = 500;
28817 -               
28818 -               log_error_write(srv, __FILE__, __LINE__,  "sb", 
28819 -                               "no proxy-handler found for:", 
28820 +
28821 +               log_error_write(srv, __FILE__, __LINE__,  "sb",
28822 +                               "no proxy-handler found for:",
28823                                 fn);
28824 -               
28825 +
28826                 return HANDLER_FINISHED;
28827         }
28828 +
28829 +       /* init handler-context */
28830 +       hctx = handler_ctx_init();
28831 +
28832 +       hctx->path_info_offset = path_info_offset;
28833 +       hctx->remote_conn      = con;
28834 +       hctx->plugin_data      = p;
28835 +       hctx->host             = host;
28836 +
28837 +       con->plugin_ctx[p->id] = hctx;
28838 +
28839 +       host->usage++;
28840 +
28841 +       /* we handle this request */
28842 +       con->mode = p->id;
28843 +
28844 +       if (p->conf.debug) {
28845 +               log_error_write(srv, __FILE__, __LINE__,  "sbd",
28846 +                               "proxy - found a host",
28847 +                               host->host, host->port);
28848 +       }
28849 +
28850         return HANDLER_GO_ON;
28851  }
28852  
28853  static handler_t mod_proxy_connection_close_callback(server *srv, connection *con, void *p_d) {
28854         plugin_data *p = p_d;
28855 -       
28856 +
28857         proxy_connection_close(srv, con->plugin_ctx[p->id]);
28858  
28859         return HANDLER_GO_ON;
28860 @@ -1276,11 +1269,11 @@
28861                 size_t i, n, k;
28862                 for (i = 0; i < srv->config_context->used; i++) {
28863                         plugin_config *s = p->config_storage[i];
28864 -                       
28865 -                       if (!s) continue; 
28866 +
28867 +                       if (!s) continue;
28868  
28869                         /* get the extensions for all configs */
28870 -                       
28871 +
28872                         for (k = 0; k < s->extensions->used; k++) {
28873                                 data_array *extension = (data_array *)s->extensions->data[k];
28874  
28875 @@ -1290,8 +1283,8 @@
28876  
28877                                         if (!host->is_disabled ||
28878                                             srv->cur_ts - host->disable_ts < 5) continue;
28879 -                       
28880 -                                       log_error_write(srv, __FILE__, __LINE__,  "sbd", 
28881 +
28882 +                                       log_error_write(srv, __FILE__, __LINE__,  "sbd",
28883                                                         "proxy - re-enabled:",
28884                                                         host->host, host->port);
28885  
28886 @@ -1317,8 +1310,8 @@
28887         p->handle_uri_clean        = mod_proxy_check_extension;
28888         p->handle_subrequest       = mod_proxy_handle_subrequest;
28889         p->handle_trigger          = mod_proxy_trigger;
28890 -       
28891 +
28892         p->data         = NULL;
28893 -       
28894 +
28895         return 0;
28896  }
28897 --- ../lighttpd-1.4.11/src/mod_proxy_core.c     1970-01-01 03:00:00.000000000 +0300
28898 +++ lighttpd-1.4.12/src/mod_proxy_core.c        2006-07-19 20:02:55.000000000 +0300
28899 @@ -0,0 +1,1713 @@
28900 +#include <string.h>
28901 +#include <stdlib.h>
28902 +#include <fcntl.h>
28903 +#include <errno.h>
28904 +#include <ctype.h>
28905 +
28906 +#include "buffer.h"
28907 +#include "array.h"
28908 +#include "log.h"
28909 +
28910 +#include "base.h"
28911 +#include "plugin.h"
28912 +#include "joblist.h"
28913 +#include "sys-files.h"
28914 +#include "inet_ntop_cache.h"
28915 +#include "http_resp.h"
28916 +#include "http_chunk.h"
28917 +#include "crc32.h"
28918 +
28919 +#include "mod_proxy_core_pool.h"       
28920 +#include "mod_proxy_core_backend.h"
28921 +#include "mod_proxy_core_backlog.h"
28922 +#include "mod_proxy_core_rewrites.h"
28923 +
28924 +#define CONFIG_PROXY_CORE_BALANCER "proxy-core.balancer"
28925 +#define CONFIG_PROXY_CORE_PROTOCOL "proxy-core.protocol"
28926 +#define CONFIG_PROXY_CORE_DEBUG "proxy-core.debug"
28927 +#define CONFIG_PROXY_CORE_BACKENDS "proxy-core.backends"
28928 +#define CONFIG_PROXY_CORE_REWRITE_REQUEST "proxy-core.rewrite-request"
28929 +#define CONFIG_PROXY_CORE_REWRITE_RESPONSE "proxy-core.rewrite-response"
28930 +
28931 +typedef enum {
28932 +       PROXY_PROTOCOL_UNSET,
28933 +       PROXY_PROTOCOL_HTTP,
28934 +       PROXY_PROTOCOL_HTTPS,
28935 +       PROXY_PROTOCOL_FASTCGI,
28936 +       PROXY_PROTOCOL_SCGI
28937 +} proxy_protocol_t;
28938 +
28939 +typedef struct {
28940 +       proxy_backends *backends;
28941 +
28942 +       proxy_backlog *backlog;
28943 +
28944 +       proxy_rewrites *request_rewrites;
28945 +       proxy_rewrites *response_rewrites;
28946 +
28947 +       int debug;
28948 +
28949 +       proxy_balance_t balancer;
28950 +       proxy_protocol_t protocol;
28951 +} plugin_config;
28952 +
28953 +typedef struct {
28954 +       PLUGIN_DATA;
28955 +
28956 +       http_resp *resp;
28957 +
28958 +       array *possible_balancers;
28959 +       array *possible_protocols;
28960 +
28961 +       /* for parsing only */
28962 +       array *backends_arr;
28963 +       buffer *protocol_buf;
28964 +       buffer *balance_buf;
28965 +
28966 +       buffer *replace_buf;
28967 +
28968 +       plugin_config **config_storage;
28969 +
28970 +       plugin_config conf;
28971 +} plugin_data;
28972 +
28973 +int array_insert_int(array *a, const char *key, int val) {
28974 +       data_integer *di;
28975 +
28976 +       if (NULL == (di = (data_integer *)array_get_unused_element(a, TYPE_INTEGER))) {
28977 +               di = data_integer_init();
28978 +       }
28979 +
28980 +       buffer_copy_string(di->key, key);
28981 +       di->value = val;
28982 +       array_insert_unique(a, (data_unset *)di);
28983 +
28984 +       return 0;
28985 +}
28986 +
28987 +INIT_FUNC(mod_proxy_core_init) {
28988 +       plugin_data *p;
28989 +
28990 +       p = calloc(1, sizeof(*p));
28991 +
28992 +       /* create some backends as long as we don't have the config-parser */
28993 +
28994 +       p->possible_balancers = array_init();
28995 +       array_insert_int(p->possible_balancers, "fair", PROXY_BALANCE_FAIR);
28996 +       array_insert_int(p->possible_balancers, "hash", PROXY_BALANCE_HASH);
28997 +       array_insert_int(p->possible_balancers, "round-robin", PROXY_BALANCE_RR);
28998 +
28999 +       p->possible_protocols = array_init();
29000 +       array_insert_int(p->possible_protocols, "http", PROXY_PROTOCOL_HTTP);
29001 +       array_insert_int(p->possible_protocols, "fastcgi", PROXY_PROTOCOL_FASTCGI);
29002 +       array_insert_int(p->possible_protocols, "scgi", PROXY_PROTOCOL_SCGI);
29003 +       array_insert_int(p->possible_protocols, "https", PROXY_PROTOCOL_HTTPS);
29004 +
29005 +       p->balance_buf = buffer_init();
29006 +       p->protocol_buf = buffer_init();
29007 +       p->replace_buf = buffer_init();
29008 +       p->backends_arr = array_init();
29009 +
29010 +       p->resp = http_response_init();
29011 +
29012 +       return p;
29013 +}
29014 +
29015 +FREE_FUNC(mod_proxy_core_free) {
29016 +       plugin_data *p = p_d;
29017 +
29018 +       if (!p) return HANDLER_GO_ON;
29019 +
29020 +       if (p->config_storage) {
29021 +               size_t i;
29022 +               for (i = 0; i < srv->config_context->used; i++) {
29023 +                       plugin_config *s = p->config_storage[i];
29024 +
29025 +                       if (!s) continue;
29026 +
29027 +                       proxy_backends_free(s->backends);
29028 +                       proxy_backlog_free(s->backlog);
29029 +
29030 +
29031 +                       free(s);
29032 +               }
29033 +               free(p->config_storage);
29034 +       }
29035 +
29036 +       array_free(p->possible_protocols);
29037 +       array_free(p->possible_balancers);
29038 +       array_free(p->backends_arr);
29039 +
29040 +       buffer_free(p->balance_buf);
29041 +       buffer_free(p->protocol_buf);
29042 +       buffer_free(p->replace_buf);
29043 +       
29044 +       http_response_free(p->resp);
29045 +
29046 +       free(p);
29047 +
29048 +       return HANDLER_GO_ON;
29049 +}
29050 +
29051 +static handler_t mod_proxy_core_config_parse_rewrites(proxy_rewrites *dest, array *src, const char *config_key) {
29052 +       data_unset *du;
29053 +       size_t j;
29054 +
29055 +       if (NULL != (du = array_get_element(src, config_key))) {
29056 +               data_array *keys = (data_array *)du;
29057 +
29058 +               if (keys->type != TYPE_ARRAY) {
29059 +                       ERROR("%s = <...>", 
29060 +                               config_key);
29061 +
29062 +                       return HANDLER_ERROR;
29063 +               }
29064 +
29065 +               /*
29066 +                * proxy-core.rewrite-request = (
29067 +                *   "_uri" => ( ... ) 
29068 +                * )
29069 +                */
29070 +
29071 +               for (j = 0; j < keys->value->used; j++) {
29072 +                       size_t k;
29073 +                       data_array *headers = (data_array *)keys->value->data[j];
29074 +
29075 +                       /* keys->key should be "_uri" and the value a array of rewrite */
29076 +                       if (headers->type != TYPE_ARRAY) {
29077 +                               ERROR("%s = ( %s => <...> ) has to a array", 
29078 +                                       config_key,
29079 +                                       BUF_STR(headers->key));
29080 +
29081 +                               return HANDLER_ERROR;
29082 +                       }
29083 +
29084 +                       if (headers->value->used > 1) {
29085 +                               ERROR("%s = ( %s => <...> ) has to a array with only one element", 
29086 +                                       config_key,
29087 +                                       BUF_STR(headers->key));
29088 +
29089 +                               return HANDLER_ERROR;
29090 +
29091 +                       }
29092 +
29093 +                       for (k = 0; k < headers->value->used; k++) {
29094 +                               data_string *rewrites = (data_string *)headers->value->data[k];
29095 +                               proxy_rewrite *rw;
29096 +
29097 +                               /* keys->key should be "_uri" and the value a array of rewrite */
29098 +                               if (rewrites->type != TYPE_STRING) {
29099 +                                       ERROR("%s = ( \"%s\" => ( \"%s\" => <value> ) ) has to a string", 
29100 +                                               config_key,
29101 +                                               BUF_STR(headers->key),
29102 +                                               BUF_STR(rewrites->key));
29103 +
29104 +                                       return HANDLER_ERROR;
29105 +                               }
29106 +                       
29107 +                               rw = proxy_rewrite_init();
29108 +
29109 +                               if (0 != proxy_rewrite_set_regex(rw, rewrites->key)) {
29110 +                                       return HANDLER_ERROR;
29111 +                               }
29112 +                               buffer_copy_string_buffer(rw->replace, rewrites->value);
29113 +                               buffer_copy_string_buffer(rw->match, rewrites->key);
29114 +                               buffer_copy_string_buffer(rw->header, headers->key);
29115 +
29116 +                               proxy_rewrites_add(dest, rw);
29117 +                       }
29118 +               }
29119 +       }
29120 +
29121 +       return HANDLER_GO_ON;
29122 +}
29123 +
29124 +
29125 +SETDEFAULTS_FUNC(mod_proxy_core_set_defaults) {
29126 +       plugin_data *p = p_d;
29127 +       size_t i, j;
29128 +
29129 +       config_values_t cv[] = {
29130 +               { CONFIG_PROXY_CORE_BACKENDS,       NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
29131 +               { CONFIG_PROXY_CORE_DEBUG,          NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
29132 +               { CONFIG_PROXY_CORE_BALANCER,       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 2 */
29133 +               { CONFIG_PROXY_CORE_PROTOCOL,       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 3 */
29134 +               { CONFIG_PROXY_CORE_REWRITE_REQUEST, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
29135 +               { CONFIG_PROXY_CORE_REWRITE_RESPONSE, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },/* 5 */
29136 +               { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
29137 +       };
29138 +
29139 +       p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
29140 +
29141 +       for (i = 0; i < srv->config_context->used; i++) {
29142 +               plugin_config *s;
29143 +               array *ca;
29144 +               proxy_backend *backend;
29145 +
29146 +               array_reset(p->backends_arr);
29147 +               buffer_reset(p->balance_buf);
29148 +               buffer_reset(p->protocol_buf);
29149 +
29150 +               s = malloc(sizeof(plugin_config));
29151 +               s->debug     = 0;
29152 +               s->balancer  = PROXY_BALANCE_UNSET;
29153 +               s->protocol  = PROXY_PROTOCOL_UNSET;
29154 +               s->backends  = proxy_backends_init();
29155 +               s->backlog   = proxy_backlog_init();
29156 +               s->response_rewrites   = proxy_rewrites_init();
29157 +               s->request_rewrites   = proxy_rewrites_init();
29158 +
29159 +               cv[0].destination = p->backends_arr;
29160 +               cv[1].destination = &(s->debug);
29161 +               cv[2].destination = p->balance_buf; /* parse into a constant */
29162 +               cv[3].destination = p->protocol_buf; /* parse into a constant */
29163 +
29164 +               buffer_reset(p->balance_buf);
29165 +
29166 +               p->config_storage[i] = s;
29167 +               ca = ((data_config *)srv->config_context->data[i])->value;
29168 +
29169 +               if (0 != config_insert_values_global(srv, ca, cv)) {
29170 +                       return HANDLER_ERROR;
29171 +               }
29172 +
29173 +               if (!buffer_is_empty(p->balance_buf)) {
29174 +                       data_integer *di;
29175 +                       
29176 +                       if (NULL == (di = (data_integer *)array_get_element(p->possible_balancers, BUF_STR(p->balance_buf)))) {
29177 +                               ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->balance_buf));
29178 +
29179 +                               return HANDLER_ERROR;
29180 +                       }
29181 +
29182 +                       s->balancer = di->value;
29183 +               }
29184 +
29185 +               if (!buffer_is_empty(p->protocol_buf)) {
29186 +                       data_integer *di;
29187 +                       
29188 +                       if (NULL == (di = (data_integer *)array_get_element(p->possible_protocols, BUF_STR(p->protocol_buf)))) {
29189 +                               ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->protocol_buf));
29190 +
29191 +                               return HANDLER_ERROR;
29192 +                       }
29193 +
29194 +                       s->protocol = di->value;
29195 +               }
29196 +
29197 +               if (p->backends_arr->used) {
29198 +                       backend = proxy_backend_init();
29199 +
29200 +                       /* check if the backends have a valid host-name */
29201 +                       for (j = 0; j < p->backends_arr->used; j++) {
29202 +                               data_string *ds = (data_string *)p->backends_arr->data[j];
29203 +
29204 +                               /* the values should be ips or hostnames */
29205 +                               if (0 != proxy_address_pool_add_string(backend->address_pool, ds->value)) {
29206 +                                       return HANDLER_ERROR;
29207 +                               }
29208 +                       }
29209 +
29210 +                       proxy_backends_add(s->backends, backend);
29211 +               }
29212 +
29213 +               if (HANDLER_GO_ON != mod_proxy_core_config_parse_rewrites(s->request_rewrites, ca, CONFIG_PROXY_CORE_REWRITE_REQUEST)) {
29214 +                       return HANDLER_ERROR;
29215 +               }
29216 +               
29217 +               if (HANDLER_GO_ON != mod_proxy_core_config_parse_rewrites(s->response_rewrites, ca, CONFIG_PROXY_CORE_REWRITE_RESPONSE)) {
29218 +                       return HANDLER_ERROR;
29219 +               }
29220 +       }
29221 +
29222 +       return HANDLER_GO_ON;
29223 +}
29224 +
29225 +
29226 +typedef enum {
29227 +       PROXY_STATE_UNSET,
29228 +       PROXY_STATE_CONNECTING,
29229 +       PROXY_STATE_CONNECTED,
29230 +       PROXY_STATE_WRITE_REQUEST_HEADER,
29231 +       PROXY_STATE_WRITE_REQUEST_BODY,
29232 +       PROXY_STATE_READ_RESPONSE_HEADER,
29233 +       PROXY_STATE_READ_RESPONSE_BODY
29234 +} proxy_state_t;
29235 +
29236 +typedef struct {
29237 +       proxy_connection *proxy_con;
29238 +       proxy_backend *proxy_backend;
29239 +
29240 +       connection *remote_con;
29241 +
29242 +       array *request_headers;
29243 +
29244 +       int is_chunked;
29245 +       
29246 +       /**
29247 +        * chunkqueues
29248 +        * - the encoded_rb is the raw network stuff
29249 +        * - the rb is filtered through the stream decoder
29250 +        *
29251 +        * - wb is the normal bytes stream
29252 +        * - encoded_wb is encoded for the network by the stream encoder
29253 +        */
29254 +       chunkqueue *recv;
29255 +       chunkqueue *recv_raw;
29256 +       chunkqueue *send_raw;
29257 +       chunkqueue *send;
29258 +       
29259 +       off_t bytes_read;
29260 +       off_t content_length;
29261 +
29262 +       proxy_state_t state;
29263 +} proxy_session;
29264 +
29265 +proxy_session *proxy_session_init(void) {
29266 +       proxy_session *sess;
29267 +
29268 +       sess = calloc(1, sizeof(*sess));
29269 +
29270 +       sess->state = PROXY_STATE_UNSET;
29271 +       sess->request_headers = array_init();
29272 +
29273 +       sess->recv = chunkqueue_init();
29274 +       sess->recv_raw = chunkqueue_init();
29275 +       sess->send_raw = chunkqueue_init();
29276 +       sess->send = chunkqueue_init();
29277 +
29278 +       sess->is_chunked = 0;
29279 +
29280 +       return sess;
29281 +}
29282 +
29283 +void proxy_session_free(proxy_session *sess) {
29284 +       if (!sess) return;
29285 +
29286 +       array_free(sess->request_headers);
29287 +
29288 +       chunkqueue_free(sess->recv);
29289 +       chunkqueue_free(sess->recv_raw);
29290 +       chunkqueue_free(sess->send_raw);
29291 +       chunkqueue_free(sess->send);
29292 +
29293 +       free(sess);
29294 +}
29295 +
29296 +handler_t proxy_connection_connect(proxy_connection *con) {
29297 +       int fd;
29298 +       
29299 +       if (-1 == (fd = socket(con->address->addr.plain.sa_family, SOCK_STREAM, 0))) {
29300 +       }
29301 +
29302 +       fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
29303 +
29304 +       con->sock->fd = fd;
29305 +       con->sock->fde_ndx = -1;
29306 +       con->sock->type = IOSOCKET_TYPE_SOCKET;
29307 +
29308 +       if (-1 == connect(fd, &(con->address->addr.plain), sizeof(con->address->addr))) {
29309 +               switch(errno) {
29310 +               case EINPROGRESS:
29311 +               case EALREADY:
29312 +               case EINTR:
29313 +                       return HANDLER_WAIT_FOR_EVENT;
29314 +               default:
29315 +                       close(fd);
29316 +                       con->sock->fd = -1;
29317 +
29318 +                       return HANDLER_ERROR;
29319 +               }
29320 +       }
29321 +
29322 +       return HANDLER_GO_ON;
29323 +}
29324 +
29325 +/**
29326 + * event-handler for idling connections
29327 + *
29328 + * unused (idling) keep-alive connections are not bound to a session
29329 + * and need their own event-handler 
29330 + *
29331 + * if the connection closes (we get a FDEVENT_IN), close our side too and 
29332 + * let the trigger-func handle the cleanup
29333 + *
29334 + * @see proxy_trigger
29335 + */
29336 +
29337 +
29338 +static handler_t proxy_handle_fdevent_idle(void *s, void *ctx, int revents) {
29339 +       server      *srv  = (server *)s;
29340 +       proxy_connection *proxy_con = ctx;
29341 +
29342 +       if (revents & FDEVENT_IN) {
29343 +               switch (proxy_con->state) {
29344 +               case PROXY_CONNECTION_STATE_IDLE:
29345 +                       proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29346 +
29347 +                       /* close + unregister have to be in the same call,
29348 +                        * otherwise we get a events for a re-opened fd */
29349 +
29350 +                       fdevent_event_del(srv->ev, proxy_con->sock);
29351 +
29352 +                       break;
29353 +               case PROXY_CONNECTION_STATE_CLOSED:
29354 +                       /* poll() is state-driven, we will get events as long as it isn't disabled
29355 +                        * the close() above should disable the events too */
29356 +                       ERROR("%s", "hurry up buddy, I got another event for a closed idle-connection");
29357 +                       break;
29358 +               default:
29359 +                       ERROR("invalid connection state: %d, should be idle", proxy_con->state);
29360 +                       break;
29361 +               }
29362 +       }
29363 +
29364 +       return HANDLER_GO_ON;
29365 +}
29366 +
29367 +void chunkqueue_skip(chunkqueue *cq, off_t skip) {
29368 +       chunk *c;
29369 +
29370 +       for (c = cq->first; c && skip; c = c->next) {
29371 +               if (skip > c->mem->used - c->offset - 1) {
29372 +                       skip -= c->mem->used - c->offset - 1;
29373 +               } else {
29374 +                       c->offset += skip;
29375 +                       skip = 0;
29376 +               }
29377 +       }
29378 +
29379 +       return;
29380 +}
29381 +
29382 +int proxy_http_stream_decoder(server *srv, proxy_session *sess, chunkqueue *raw, chunkqueue *decoded) {
29383 +       chunk *c;
29384 +
29385 +       if (raw->first == NULL) return 0;
29386 +
29387 +       if (sess->is_chunked) {
29388 +               do {
29389 +                       /* the start should always be a chunk-length */
29390 +                       off_t chunk_len = 0;
29391 +                       char *err = NULL;
29392 +                       int chunklen_strlen = 0;
29393 +                       char ch;
29394 +                       off_t we_have = 0, we_need = 0;
29395 +
29396 +                       c = raw->first;
29397 +
29398 +                       if (c->mem->used == 0) return 0;
29399 +
29400 +                       chunk_len = strtol(BUF_STR(c->mem) + c->offset, &err, 16);
29401 +                       if (!(*err == ' ' || *err == '\r' || *err == ';')) {
29402 +                               if (*err == '\0') {
29403 +                                       /* we just need more data */
29404 +                                       return 0;
29405 +                               }
29406 +                               return -1;
29407 +                       }
29408 +
29409 +                       if (chunk_len < 0) {
29410 +                               ERROR("chunk_len is negative: %Ld", chunk_len);
29411 +                               return -1;
29412 +                       }
29413 +
29414 +                       chunklen_strlen = err - (BUF_STR(c->mem) + c->offset);
29415 +                       chunklen_strlen++; /* skip the err-char */ 
29416 +                       
29417 +                       do {
29418 +                               ch = BUF_STR(c->mem)[c->offset + chunklen_strlen];
29419 +       
29420 +                               switch (ch) {
29421 +                               case '\n':
29422 +                               case '\0':
29423 +                                       /* bingo, chunk-header is finished */
29424 +                                       break;
29425 +                               default:
29426 +                                       break;
29427 +                               }
29428 +                               chunklen_strlen++;
29429 +                       } while (ch != '\n' && c != '\0');
29430 +
29431 +                       if (ch != '\n') {
29432 +                               ERROR("%s", "missing the CRLF");
29433 +                               return 0;
29434 +                       }
29435 +
29436 +                       we_need = chunk_len + chunklen_strlen + 2;
29437 +                       /* do we have the full chunk ? */
29438 +                       for (c = raw->first; c; c = c->next) {
29439 +                               we_have += c->mem->used - 1 - c->offset;
29440 +
29441 +                               /* we have enough, jump out */
29442 +                               if (we_have > we_need) break;
29443 +                       }
29444 +
29445 +                       /* get more data */
29446 +                       if (we_have < we_need) {
29447 +                               return 0;
29448 +                       }
29449 +
29450 +                       /* skip the chunk-header */
29451 +                       chunkqueue_skip(raw, chunklen_strlen);
29452 +
29453 +                       /* final chunk */
29454 +                       if (chunk_len == 0) {
29455 +                               chunkqueue_skip(raw, 2);
29456 +
29457 +                               return 1;
29458 +                       }
29459 +
29460 +                       /* we have enough, copy the data */     
29461 +                       for (c = raw->first; c && chunk_len; c = c->next) {
29462 +                               off_t we_want = 0;
29463 +                               buffer *b = chunkqueue_get_append_buffer(decoded);
29464 +
29465 +                               we_want = chunk_len > (c->mem->used - c->offset - 1) ? c->mem->used - c->offset - 1: chunk_len;
29466 +
29467 +                               buffer_copy_string_len(b, c->mem->ptr + c->offset, we_want);
29468 +
29469 +                               c->offset += we_want;
29470 +                               chunk_len -= we_want;
29471 +                       }
29472 +
29473 +                       /* skip the \r\n */
29474 +                       chunkqueue_skip(raw, 2);
29475 +
29476 +                       /* we are done, give the connection to someone else */
29477 +                       chunkqueue_remove_finished_chunks(raw);
29478 +               } while (1);
29479 +       } else {
29480 +               /* no chunked encoding, ok, perhaps a content-length ? */
29481 +
29482 +               chunkqueue_remove_finished_chunks(raw);
29483 +               for (c = raw->first; c; c = c->next) {
29484 +                       buffer *b;
29485 +
29486 +                       if (c->mem->used == 0) continue;
29487 +                      
29488 +                       b = chunkqueue_get_append_buffer(decoded);
29489 +
29490 +                       sess->bytes_read += c->mem->used - c->offset - 1;
29491 +
29492 +                       buffer_copy_string_len(b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
29493 +
29494 +                       c->offset = c->mem->used - 1;
29495 +
29496 +                       if (sess->bytes_read == sess->content_length) {
29497 +                               break;
29498 +                       }
29499 +
29500 +               }
29501 +               if (sess->bytes_read == sess->content_length) {
29502 +                       return 1; /* finished */
29503 +               }
29504 +       }
29505 +
29506 +       return 0;
29507 +}
29508 +/* don't call any proxy functions directly */
29509 +static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) {
29510 +       server      *srv  = (server *)s;
29511 +       proxy_session *sess = ctx;
29512 +
29513 +       if (revents & FDEVENT_OUT) {
29514 +               switch (sess->state) {
29515 +               case PROXY_STATE_CONNECTING: /* delayed connect */
29516 +               case PROXY_STATE_WRITE_REQUEST_HEADER:
29517 +               case PROXY_STATE_WRITE_REQUEST_BODY:
29518 +                       /* we are still connection */
29519 +
29520 +                       joblist_append(srv, sess->remote_con);
29521 +                       break;
29522 +               default:
29523 +                       ERROR("oops, unexpected state for fdevent-out %d", sess->state);
29524 +                       break;
29525 +               }
29526 +       } else if (revents & FDEVENT_IN) {
29527 +               chunk *c;
29528 +
29529 +               switch (sess->state) {
29530 +               case PROXY_STATE_READ_RESPONSE_HEADER:
29531 +                       /* call our header parser */
29532 +                       joblist_append(srv, sess->remote_con);
29533 +                       break;
29534 +               case PROXY_STATE_READ_RESPONSE_BODY:
29535 +                       /* we should be in the WRITE state now, 
29536 +                        * just read in the content and forward it to the outgoing connection
29537 +                        * */
29538 +
29539 +                       chunkqueue_remove_finished_chunks(sess->recv_raw);
29540 +                       switch (srv->network_backend_read(srv, sess->remote_con, sess->proxy_con->sock, sess->recv_raw)) {
29541 +                       case NETWORK_STATUS_CONNECTION_CLOSE:
29542 +                               fdevent_event_del(srv->ev,sess->proxy_con->sock);
29543 +
29544 +                               /* the connection is gone
29545 +                                * make the connect */
29546 +                               sess->remote_con->file_finished = 1;
29547 +                               sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29548 +
29549 +                       case NETWORK_STATUS_SUCCESS:
29550 +                               /* read even more, do we have all the content */
29551 +
29552 +                               /* how much do we want to read ? */
29553 +                               
29554 +                               /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
29555 +
29556 +                               switch (proxy_http_stream_decoder(srv, sess, sess->recv_raw, sess->recv)) {
29557 +                               case 0:
29558 +                                       /* need more */
29559 +                                       break;
29560 +                               case -1:
29561 +                                       /* error */
29562 +                                       break;
29563 +                               case 1:
29564 +                                       /* we are done */
29565 +                                       sess->remote_con->file_finished = 1;
29566 +
29567 +                                       break;
29568 +                               }
29569 +                               chunkqueue_remove_finished_chunks(sess->recv_raw);
29570 +
29571 +                               /* copy the content to the next cq */
29572 +                               for (c = sess->recv->first; c; c = c->next) {
29573 +                                       if (c->mem->used == 0) continue;
29574 +
29575 +                                       http_chunk_append_mem(srv, sess->remote_con, c->mem->ptr + c->offset, c->mem->used - c->offset);
29576 +       
29577 +                                       c->offset = c->mem->used - 1;
29578 +
29579 +                               }
29580 +                               chunkqueue_remove_finished_chunks(sess->recv);
29581 +
29582 +                               if (sess->remote_con->file_finished) {
29583 +                                       /* send final HTTP-Chunk packet */
29584 +                                       http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
29585 +                               }
29586 +                               
29587 +                               break;
29588 +                       default:
29589 +                               ERROR("%s", "oops, we failed to read");
29590 +                               break;
29591 +                       }
29592 +
29593 +                       joblist_append(srv, sess->remote_con);
29594 +                       break;
29595 +               default:
29596 +                       ERROR("oops, unexpected state for fdevent-in %d", sess->state);
29597 +                       break;
29598 +               }
29599 +       }
29600 +
29601 +       if (revents & FDEVENT_HUP) {
29602 +               /* someone closed our connection */
29603 +               switch (sess->state) {
29604 +               case PROXY_STATE_CONNECTING:
29605 +                       /* let the getsockopt() catch this */
29606 +                       joblist_append(srv, sess->remote_con);
29607 +                       break;
29608 +               default:
29609 +                       ERROR("oops, unexpected state for fdevent-hup %d", sess->state);
29610 +                       break;
29611 +               }
29612 +       }
29613 +
29614 +       return HANDLER_GO_ON;
29615 +}
29616 +
29617 +int pcre_replace(pcre *match, buffer *replace, buffer *match_buf, buffer *result) {
29618 +       const char *pattern = replace->ptr;
29619 +       size_t pattern_len = replace->used - 1;
29620 +
29621 +# define N 10
29622 +       int ovec[N * 3];
29623 +       int n;
29624 +
29625 +       if ((n = pcre_exec(match, NULL, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
29626 +               if (n != PCRE_ERROR_NOMATCH) {
29627 +                       return n;
29628 +               }
29629 +       } else {
29630 +               const char **list;
29631 +               size_t start, end;
29632 +               size_t k;
29633 +
29634 +               /* it matched */
29635 +               pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
29636 +
29637 +               /* search for $[0-9] */
29638 +
29639 +               buffer_reset(result);
29640 +
29641 +               start = 0; end = pattern_len;
29642 +               for (k = 0; k < pattern_len; k++) {
29643 +                       if ((pattern[k] == '$') &&
29644 +                           isdigit((unsigned char)pattern[k + 1])) {
29645 +                               /* got one */
29646 +
29647 +                               size_t num = pattern[k + 1] - '0';
29648 +
29649 +                               end = k;
29650 +
29651 +                               buffer_append_string_len(result, pattern + start, end - start);
29652 +
29653 +                               /* n is always > 0 */
29654 +                               if (num < (size_t)n) {
29655 +                                       buffer_append_string(result, list[num]);
29656 +                               }
29657 +
29658 +                               k++;
29659 +                               start = k + 1;
29660 +                       }
29661 +               }
29662 +
29663 +               buffer_append_string_len(result, pattern + start, pattern_len - start);
29664 +
29665 +               pcre_free(list);
29666 +       }
29667 +
29668 +       return n;
29669 +}
29670 +
29671 +/**
29672 + * generate a HTTP/1.1 proxy request from the set of request-headers
29673 + *
29674 + * TODO: this is HTTP-proxy specific and will be moved moved into a separate backed
29675 + *
29676 + */
29677 +int proxy_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
29678 +       buffer *b;
29679 +       size_t i;
29680 +       
29681 +       b = chunkqueue_get_append_buffer(cq);
29682 +
29683 +       /* request line */
29684 +       buffer_copy_string(b, get_http_method_name(con->request.http_method));
29685 +       BUFFER_APPEND_STRING_CONST(b, " ");
29686 +
29687 +       /* check if we want to rewrite the uri */
29688 +
29689 +       for (i = 0; i < p->conf.request_rewrites->used; i++) {
29690 +               proxy_rewrite *rw = p->conf.request_rewrites->ptr[i];
29691 +
29692 +               if (buffer_is_equal_string(rw->header, CONST_STR_LEN("_uri"))) {
29693 +                       int ret;
29694 +
29695 +                       if ((ret = pcre_replace(rw->regex, rw->replace, con->request.uri, p->replace_buf)) < 0) {
29696 +                               switch (ret) {
29697 +                               case PCRE_ERROR_NOMATCH:
29698 +                                       /* hmm, ok. no problem */
29699 +                                       buffer_append_string_buffer(b, con->request.uri);
29700 +                                       break;
29701 +                               default:
29702 +                                       TRACE("oops, pcre_replace failed with: %d", ret);
29703 +                                       break;
29704 +                               }
29705 +                       } else {
29706 +                               buffer_append_string_buffer(b, p->replace_buf);
29707 +                       }
29708 +
29709 +                       break;
29710 +               }
29711 +       }
29712 +
29713 +       if (i == p->conf.request_rewrites->used) {
29714 +               /* not found */
29715 +               buffer_append_string_buffer(b, con->request.uri);
29716 +       }
29717 +
29718 +       BUFFER_APPEND_STRING_CONST(b, " HTTP/1.1\r\n");
29719 +
29720 +       for (i = 0; i < sess->request_headers->used; i++) {
29721 +               data_string *ds;
29722 +
29723 +               ds = (data_string *)sess->request_headers->data[i];
29724 +
29725 +               buffer_append_string_buffer(b, ds->key);
29726 +               BUFFER_APPEND_STRING_CONST(b, ": ");
29727 +               buffer_append_string_buffer(b, ds->value);
29728 +               BUFFER_APPEND_STRING_CONST(b, "\r\n");
29729 +       }
29730 +
29731 +       BUFFER_APPEND_STRING_CONST(b, "\r\n");
29732 +       
29733 +       return 0;
29734 +}
29735 +
29736 +void proxy_set_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
29737 +       data_string *ds_dst;
29738 +
29739 +       if (NULL != (ds_dst = (data_string *)array_get_element(hdrs, key))) {
29740 +               buffer_copy_string_len(ds_dst->value, value, val_len);
29741 +               return;
29742 +       }
29743 +
29744 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
29745 +               ds_dst = data_string_init();
29746 +       }
29747 +
29748 +       buffer_copy_string_len(ds_dst->key, key, key_len);
29749 +       buffer_copy_string_len(ds_dst->value, value, val_len);
29750 +       array_insert_unique(hdrs, (data_unset *)ds_dst);
29751 +}
29752 +
29753 +void proxy_append_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
29754 +       data_string *ds_dst;
29755 +
29756 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
29757 +               ds_dst = data_string_init();
29758 +       }
29759 +
29760 +       buffer_copy_string_len(ds_dst->key, key, key_len);
29761 +       buffer_copy_string_len(ds_dst->value, value, val_len);
29762 +       array_insert_unique(hdrs, (data_unset *)ds_dst);
29763 +}
29764 +
29765 +
29766 +/**
29767 + * build the request-header array and call the backend specific request formater
29768 + * to fill the chunkqueue
29769 + */
29770 +int proxy_get_request_header(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
29771 +       /* request line */
29772 +       const char *remote_ip;
29773 +       size_t i;
29774 +
29775 +       remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
29776 +       proxy_append_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-For"), remote_ip, strlen(remote_ip));
29777 +
29778 +       /* http_host is NOT is just a pointer to a buffer
29779 +        * which is NULL if it is not set */
29780 +       if (con->request.http_host &&
29781 +           !buffer_is_empty(con->request.http_host)) {
29782 +               proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Host"), CONST_BUF_LEN(con->request.http_host));
29783 +       }
29784 +       if (con->conf.is_ssl) {
29785 +               proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("https"));
29786 +       } else {
29787 +               proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("http"));
29788 +       }
29789 +
29790 +       /* request header */
29791 +       for (i = 0; i < con->request.headers->used; i++) {
29792 +               data_string *ds;
29793 +               size_t k;
29794 +
29795 +               ds = (data_string *)con->request.headers->data[i];
29796 +
29797 +               if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
29798 +
29799 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
29800 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
29801 +
29802 +               for (k = 0; k < p->conf.request_rewrites->used; k++) {
29803 +                       proxy_rewrite *rw = p->conf.request_rewrites->ptr[k];
29804 +
29805 +                       if (buffer_is_equal(rw->header, ds->key)) {
29806 +                               int ret;
29807 +
29808 +                               if ((ret = pcre_replace(rw->regex, rw->replace, ds->value, p->replace_buf)) < 0) {
29809 +                                       switch (ret) {
29810 +                                       case PCRE_ERROR_NOMATCH:
29811 +                                               /* hmm, ok. no problem */
29812 +                                               proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
29813 +                                               break;
29814 +                                       default:
29815 +                                               TRACE("oops, pcre_replace failed with: %d", ret);
29816 +                                               break;
29817 +                                       }
29818 +                               } else {
29819 +                                       proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(p->replace_buf));
29820 +                               }
29821 +
29822 +                               break;
29823 +                       }
29824 +               }
29825 +
29826 +               if (k == p->conf.request_rewrites->used) {
29827 +                       proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
29828 +               }
29829 +       }
29830 +
29831 +       proxy_get_request_chunk(srv, con, p, sess, sess->send_raw);
29832 +
29833 +       return 0;
29834 +}
29835 +
29836 +/**
29837 + * parse the response header
29838 + *
29839 + * NOTE: this can be used by all backends as they all send a HTTP-Response a clean block
29840 + * - fastcgi needs some decoding for the protocol
29841 + */
29842 +parse_status_t proxy_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
29843 +       int have_content_length = 0;
29844 +       size_t i;
29845 +
29846 +       http_response_reset(p->resp);
29847 +       
29848 +       switch (http_response_parse_cq(cq, p->resp)) {
29849 +       case PARSE_ERROR:
29850 +               /* parsing failed */
29851 +
29852 +               return PARSE_ERROR;
29853 +       case PARSE_NEED_MORE:
29854 +               return PARSE_NEED_MORE;
29855 +       case PARSE_SUCCESS:
29856 +               con->http_status = p->resp->status;
29857 +
29858 +               chunkqueue_remove_finished_chunks(cq);
29859 +
29860 +               sess->content_length = -1;
29861 +
29862 +               /* copy the http-headers */
29863 +               for (i = 0; i < p->resp->headers->used; i++) {
29864 +                       const char *ign[] = { "Status", "Connection", NULL };
29865 +                       size_t j, k;
29866 +                       data_string *ds;
29867 +
29868 +                       data_string *header = (data_string *)p->resp->headers->data[i];
29869 +
29870 +                       /* some headers are ignored by default */
29871 +                       for (j = 0; ign[j]; j++) {
29872 +                               if (0 == strcasecmp(ign[j], header->key->ptr)) break;
29873 +                       }
29874 +                       if (ign[j]) continue;
29875 +
29876 +                       if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
29877 +                               /* CGI/1.1 rev 03 - 7.2.1.2 */
29878 +                               if (con->http_status == 0) con->http_status = 302;
29879 +                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
29880 +                               have_content_length = 1;
29881 +
29882 +                               sess->content_length = strtol(header->value->ptr, NULL, 10);
29883 +
29884 +                               if (sess->content_length < 0) {
29885 +                                       return PARSE_ERROR;
29886 +                               }
29887 +                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Transfer-Encoding"))) {
29888 +                               if (strstr(header->value->ptr, "chunked")) {
29889 +                                       sess->is_chunked = 1;
29890 +                               }
29891 +                               /* ignore the header */
29892 +                               continue;
29893 +                       }
29894 +                       
29895 +                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
29896 +                               ds = data_response_init();
29897 +                       }
29898 +
29899 +
29900 +                       buffer_copy_string_buffer(ds->key, header->key);
29901 +
29902 +                       for (k = 0; k < p->conf.response_rewrites->used; k++) {
29903 +                               proxy_rewrite *rw = p->conf.response_rewrites->ptr[k];
29904 +
29905 +                               if (buffer_is_equal(rw->header, header->key)) {
29906 +                                       int ret;
29907 +       
29908 +                                       if ((ret = pcre_replace(rw->regex, rw->replace, header->value, p->replace_buf)) < 0) {
29909 +                                               switch (ret) {
29910 +                                               case PCRE_ERROR_NOMATCH:
29911 +                                                       /* hmm, ok. no problem */
29912 +                                                       buffer_append_string_buffer(ds->value, header->value);
29913 +                                                       break;
29914 +                                               default:
29915 +                                                       TRACE("oops, pcre_replace failed with: %d", ret);
29916 +                                                       break;
29917 +                                               }
29918 +                                       } else {
29919 +                                               buffer_append_string_buffer(ds->value, p->replace_buf);
29920 +                                       }
29921 +
29922 +                                       break;
29923 +                               }
29924 +                       }
29925 +
29926 +                       if (k == p->conf.response_rewrites->used) {
29927 +                               buffer_copy_string_buffer(ds->value, header->value);
29928 +                       }
29929 +
29930 +                       array_insert_unique(con->response.headers, (data_unset *)ds);
29931 +               }
29932 +
29933 +               /* does the client allow us to send chunked encoding ? */
29934 +               if (con->request.http_version == HTTP_VERSION_1_1 &&
29935 +                   !have_content_length) {
29936 +                       con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
29937 +               }
29938 +
29939 +               break;
29940 +       }
29941 +
29942 +       return PARSE_SUCCESS; /* we have a full header */
29943 +}
29944 +
29945 +/* we are event-driven
29946 + * 
29947 + * the first entry is connect() call, if the doesn't need a event 
29948 + *
29949 + * a bit boring
29950 + * - connect (+ delayed connect)
29951 + * - write header + content
29952 + * - read header + content
29953 + *
29954 + * as soon as have read the response header we switch con->file_started and return HANDLER_GO_ON to
29955 + * tell the core we are ready to stream out the content.
29956 + *  */
29957 +handler_t proxy_state_engine(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
29958 +       /* do we have a connection ? */
29959 +
29960 +       if (sess->state == PROXY_STATE_UNSET) {
29961 +               /* we are not started yet */
29962 +               switch(proxy_connection_connect(sess->proxy_con)) {
29963 +               case HANDLER_WAIT_FOR_EVENT:
29964 +                       /* waiting on the connect call */
29965 +
29966 +                       fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
29967 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
29968 +
29969 +                       sess->state = PROXY_STATE_CONNECTING;
29970 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
29971 +                       
29972 +                       return HANDLER_WAIT_FOR_EVENT;
29973 +               case HANDLER_GO_ON:
29974 +                       /* we are connected */
29975 +                       sess->state = PROXY_STATE_CONNECTED;
29976 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
29977 +                       fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
29978 +
29979 +                       break;
29980 +               case HANDLER_ERROR:
29981 +               default:
29982 +                       /* not good, something failed */
29983 +                       return HANDLER_ERROR;
29984 +               
29985 +               }
29986 +       } else if (sess->state == PROXY_STATE_CONNECTING) {
29987 +               int socket_error;
29988 +               socklen_t socket_error_len = sizeof(socket_error);
29989 +
29990 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
29991 +
29992 +               if (0 != getsockopt(sess->proxy_con->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
29993 +                       ERROR("getsockopt failed:", strerror(errno));
29994 +
29995 +                       return HANDLER_ERROR;
29996 +               }
29997 +               if (socket_error != 0) {
29998 +                       switch (socket_error) {
29999 +                       case ECONNREFUSED:
30000 +                               /* there is no-one on the other side */
30001 +                               sess->proxy_con->address->disabled_until = srv->cur_ts + 2;
30002 +
30003 +                               TRACE("address %s refused us, disabling for 2 sec", sess->proxy_con->address->name->ptr);
30004 +                               break;
30005 +                       case EHOSTUNREACH:
30006 +                               /* there is no-one on the other side */
30007 +                               sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
30008 +
30009 +                               TRACE("host %s is unreachable, disabling for 60 sec", sess->proxy_con->address->name->ptr);
30010 +                               break;
30011 +                       default:
30012 +                               sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
30013 +
30014 +                               TRACE("connected finally failed: %s (%d)", strerror(socket_error), socket_error);
30015 +
30016 +                               TRACE("connect to address %s failed and I don't know why, disabling for 10 sec", sess->proxy_con->address->name->ptr);
30017 +
30018 +                               break;
30019 +                       }
30020 +
30021 +                       sess->proxy_con->address->state = PROXY_ADDRESS_STATE_DISABLED;
30022 +
30023 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
30024 +                       return HANDLER_COMEBACK;
30025 +               }
30026 +
30027 +               sess->state = PROXY_STATE_CONNECTED;
30028 +               sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
30029 +       }
30030 +
30031 +       if (sess->state == PROXY_STATE_CONNECTED) {
30032 +               /* build the header */
30033 +               proxy_get_request_header(srv, con, p, sess);
30034 +
30035 +               sess->state = PROXY_STATE_WRITE_REQUEST_HEADER;
30036 +       }
30037 +
30038 +       switch (sess->state) {
30039 +       case PROXY_STATE_WRITE_REQUEST_HEADER:
30040 +               /* create the request-packet */ 
30041 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
30042 +
30043 +               switch (srv->network_backend_write(srv, con, sess->proxy_con->sock, sess->send_raw)) {
30044 +               case NETWORK_STATUS_SUCCESS:
30045 +                       sess->state = PROXY_STATE_WRITE_REQUEST_BODY;
30046 +                       break;
30047 +               case NETWORK_STATUS_WAIT_FOR_EVENT:
30048 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
30049 +
30050 +                       return HANDLER_WAIT_FOR_EVENT;
30051 +               case NETWORK_STATUS_CONNECTION_CLOSE:
30052 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
30053 +
30054 +                       /* this connection is closed, restart the request with a new connection */
30055 +
30056 +                       return HANDLER_COMEBACK;
30057 +               default:
30058 +                       return HANDLER_ERROR;
30059 +               }
30060 +               /* fall through */
30061 +       case PROXY_STATE_WRITE_REQUEST_BODY:
30062 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
30063 +               sess->state = PROXY_STATE_READ_RESPONSE_HEADER;
30064 +
30065 +       case PROXY_STATE_READ_RESPONSE_HEADER:
30066 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
30067 +
30068 +               chunkqueue_remove_finished_chunks(sess->recv_raw);
30069 +
30070 +               switch (srv->network_backend_read(srv, con, sess->proxy_con->sock, sess->recv_raw)) {
30071 +               case NETWORK_STATUS_SUCCESS:
30072 +                       /* we read everything from the socket, do we have a full header ? */
30073 +
30074 +                       switch (proxy_parse_response_header(srv, con, p, sess, sess->recv_raw)) {
30075 +                       case PARSE_ERROR:
30076 +                               con->http_status = 502; /* bad gateway */
30077 +
30078 +                               return HANDLER_FINISHED;
30079 +                       case PARSE_NEED_MORE:
30080 +                               /* we need more */
30081 +                               fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30082 +
30083 +                               return HANDLER_WAIT_FOR_EVENT;
30084 +                       case PARSE_SUCCESS:
30085 +                               break;
30086 +                       default:
30087 +                               return HANDLER_ERROR;
30088 +                       }
30089 +                       
30090 +                       con->file_started = 1;
30091 +
30092 +                       sess->state = PROXY_STATE_READ_RESPONSE_BODY;
30093 +
30094 +                       /**
30095 +                        * set the event to pass the content through to the server
30096 +                        *
30097 +                        * this triggers the event-handler
30098 +                        * @see proxy_handle_fdevent
30099 +                        */
30100 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30101 +
30102 +                       return HANDLER_GO_ON; /* tell http_response_prepare that we are done with the header */
30103 +               case NETWORK_STATUS_WAIT_FOR_EVENT:
30104 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30105 +                       return HANDLER_WAIT_FOR_EVENT;
30106 +               case NETWORK_STATUS_CONNECTION_CLOSE:
30107 +                       if (chunkqueue_length(sess->recv_raw) == 0) {
30108 +                               /* the connection went away before we got something back */
30109 +                               sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
30110 +
30111 +                               /**
30112 +                                * we might run into a 'race-condition' 
30113 +                                *
30114 +                                * 1. proxy-con is keep-alive, idling and just being closed (FDEVENT_IN) [fd=27]
30115 +                                * 2. new connection comes in, we use the idling connection [fd=14]
30116 +                                * 3. we write(), successful [to fd=27]
30117 +                                * 3. we read() ... and finally receive the close-event for the connection
30118 +                                */
30119 +
30120 +                               con->http_status = 500;
30121 +
30122 +                               ERROR("++ %s", "oops, connection got closed while we were reading from it");
30123 +                               return HANDLER_FINISHED;
30124 +                       }
30125 +
30126 +                       ERROR("%s", "conn-close after header-read");
30127 +                               
30128 +                       break;
30129 +               default:
30130 +                       ERROR("++ %s", "oops, something went wrong while reading");
30131 +                       return HANDLER_ERROR;
30132 +               }
30133 +       case PROXY_STATE_READ_RESPONSE_BODY:
30134 +               /* if we do everything right, we won't get call for this state-anymore */
30135 +
30136 +               ERROR("%s", "PROXY_STATE_READ_RESPONSE_BODY");
30137 +               
30138 +               break;
30139 +       }
30140 +
30141 +       return HANDLER_GO_ON;
30142 +}
30143 +
30144 +proxy_backend *proxy_get_backend(server *srv, connection *con, plugin_data *p) {
30145 +       size_t i;
30146 +
30147 +       for (i = 0; i < p->conf.backends->used; i++) {
30148 +               proxy_backend *backend = p->conf.backends->ptr[i];
30149 +
30150 +               return backend;
30151 +       }
30152 +
30153 +       return NULL;
30154 +}
30155 +
30156 +/**
30157 + * choose a available address from the address-pool
30158 + *
30159 + * the backend has different balancers 
30160 + */
30161 +proxy_address *proxy_backend_balance(server *srv, connection *con, proxy_backend *backend) {
30162 +       size_t i;
30163 +       proxy_address_pool *address_pool = backend->address_pool;
30164 +       unsigned long last_max; /* for the HASH balancer */
30165 +       proxy_address *address = NULL, *cur_address = NULL;
30166 +       int active_addresses = 0, rand_ndx;
30167 +
30168 +       switch(backend->balancer) {
30169 +       case PROXY_BALANCE_HASH:
30170 +               /* hash balancing */
30171 +
30172 +               for (i = 0, last_max = ULONG_MAX; i < address_pool->used; i++) {
30173 +                       unsigned long cur_max;
30174 +
30175 +                       cur_address = address_pool->ptr[i];
30176 +
30177 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30178 +
30179 +                       cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
30180 +                               generate_crc32c(CONST_BUF_LEN(cur_address->name)) + /* we can cache this */
30181 +                               generate_crc32c(CONST_BUF_LEN(con->uri.authority));
30182 +#if 0
30183 +                       TRACE("hash-election: %s - %s - %s: %ld", 
30184 +                                       con->uri.path->ptr,
30185 +                                       cur_address->name->ptr,
30186 +                                       con->uri.authority->ptr,
30187 +                                       cur_max);
30188 +#endif
30189 +                       if (address == NULL || (cur_max > last_max)) {
30190 +                               last_max = cur_max;
30191 +
30192 +                               address = cur_address;
30193 +                       }
30194 +               }
30195 +
30196 +               break;
30197 +       case PROXY_BALANCE_FAIR:
30198 +               /* fair balancing */
30199 +
30200 +               for (i = 0; i < address_pool->used; i++) {
30201 +                       cur_address = address_pool->ptr[i];
30202 +
30203 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30204 +
30205 +                       /* the address is up, use it */
30206 +
30207 +                       address = cur_address;
30208 +
30209 +                       break;
30210 +               }
30211 +
30212 +               break;
30213 +       case PROXY_BALANCE_RR:
30214 +               /* round robin */
30215 +
30216 +               /**
30217 +                * instead of real RoundRobin we just do a RandomSelect
30218 +                *
30219 +                * it is state-less and has the same distribution
30220 +                */
30221 +
30222 +               active_addresses = 0;
30223 +               
30224 +               for (i = 0; i < address_pool->used; i++) {
30225 +                       cur_address = address_pool->ptr[i];
30226 +
30227 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30228 +
30229 +                       active_addresses++;
30230 +               }
30231 +
30232 +               rand_ndx = (int) (1.0 * active_addresses * rand()/(RAND_MAX));
30233 +       
30234 +               active_addresses = 0;
30235 +               for (i = 0; i < address_pool->used; i++) {
30236 +                       cur_address = address_pool->ptr[i];
30237 +
30238 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30239 +
30240 +                       address = cur_address;
30241 +
30242 +                       if (rand_ndx == active_addresses++) break;
30243 +               }
30244 +
30245 +               break;
30246 +       default:
30247 +               break;
30248 +       }
30249 +
30250 +       return address;
30251 +}
30252 +
30253 +static int mod_proxy_core_patch_connection(server *srv, connection *con, plugin_data *p) {
30254 +       size_t i, j;
30255 +       plugin_config *s = p->config_storage[0];
30256 +
30257 +       /* global defaults */
30258 +       PATCH_OPTION(balancer);
30259 +       PATCH_OPTION(debug);
30260 +       PATCH_OPTION(backends);
30261 +       PATCH_OPTION(backlog);
30262 +       PATCH_OPTION(protocol);
30263 +       PATCH_OPTION(request_rewrites);
30264 +       PATCH_OPTION(response_rewrites);
30265 +
30266 +       /* skip the first, the global context */
30267 +       for (i = 1; i < srv->config_context->used; i++) {
30268 +               data_config *dc = (data_config *)srv->config_context->data[i];
30269 +               s = p->config_storage[i];
30270 +
30271 +               /* condition didn't match */
30272 +               if (!config_check_cond(srv, con, dc)) continue;
30273 +
30274 +               /* merge config */
30275 +               for (j = 0; j < dc->value->used; j++) {
30276 +                       data_unset *du = dc->value->data[j];
30277 +
30278 +                       if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_BACKENDS))) {
30279 +                               PATCH_OPTION(backends);
30280 +                               PATCH_OPTION(backlog);
30281 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_DEBUG))) {
30282 +                               PATCH_OPTION(debug);
30283 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_BALANCER))) {
30284 +                               PATCH_OPTION(balancer);
30285 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_PROTOCOL))) {
30286 +                               PATCH_OPTION(protocol);
30287 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_REWRITE_REQUEST))) {
30288 +                               PATCH_OPTION(request_rewrites);
30289 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_REWRITE_RESPONSE))) {
30290 +                               PATCH_OPTION(response_rewrites);
30291 +                       }
30292 +               }
30293 +       }
30294 +
30295 +       return 0;
30296 +}
30297 +
30298 +
30299 +SUBREQUEST_FUNC(mod_proxy_core_check_extension) {
30300 +       plugin_data *p = p_d;
30301 +       proxy_session *sess = con->plugin_ctx[p->id]; /* if this is the second round, sess is already prepared */
30302 +
30303 +       /* check if we have a matching conditional for this request */
30304 +
30305 +       if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
30306 +
30307 +       mod_proxy_core_patch_connection(srv, con, p);
30308 +
30309 +       if (p->conf.backends->used == 0) return HANDLER_GO_ON;
30310 +
30311 +       /* 
30312 +        * 0. build session
30313 +        * 1. get a proxy connection
30314 +        * 2. create the http-request header
30315 +        * 3. stream the content to the backend 
30316 +        * 4. wait for http-response header 
30317 +        * 5. decode the response + parse the response
30318 +        * 6. stream the response-content to the client 
30319 +        * 7. kill session
30320 +        * */
30321 +
30322 +       if (!sess) {
30323 +               /* a session lives for a single request */
30324 +               sess = proxy_session_init();
30325 +
30326 +               con->plugin_ctx[p->id] = sess;
30327 +               con->mode = p->id;
30328 +
30329 +               sess->remote_con = con;
30330 +       }
30331 +
30332 +       switch (sess->state) {
30333 +       case PROXY_STATE_CONNECTING:
30334 +               /* this connections is waited 10 seconds to connect to the backend
30335 +                * and didn't got a successful connection yet, sending timeout */
30336 +               if (srv->cur_ts - con->request_start > 10) {
30337 +                       con->http_status = 504; /* gateway timeout */
30338 +                       con->file_finished = 1;
30339 +
30340 +                       if (sess->proxy_con) {
30341 +                               /* if we are waiting for a proxy-connection right now, close it */
30342 +                               proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30343 +       
30344 +                               fdevent_event_del(srv->ev, sess->proxy_con->sock);
30345 +                               fdevent_unregister(srv->ev, sess->proxy_con->sock);
30346 +
30347 +                               proxy_connection_free(sess->proxy_con);
30348 +                       
30349 +                               sess->proxy_con = NULL;
30350 +                       }
30351 +                       
30352 +                       return HANDLER_FINISHED;
30353 +               }
30354 +       default:
30355 +               /* handle-request-timeout,  */
30356 +               if (srv->cur_ts - con->request_start > 60) {
30357 +                       TRACE("request runs longer than 60sec: current state: %d", sess->state);
30358 +               }
30359 +               break;
30360 +       }
30361 +
30362 +       /* if the WRITE fails from the start, restart the connection */
30363 +       while (1) {
30364 +               if (sess->proxy_con == NULL) {
30365 +                       proxy_address *address = NULL;
30366 +                       if (NULL == (sess->proxy_backend = proxy_get_backend(srv, con, p))) {
30367 +                               /* no connection pool for this location */
30368 +                               SEGFAULT();
30369 +                       }
30370 +
30371 +                       sess->proxy_backend->balancer = p->conf.balancer;
30372 +
30373 +                       /**
30374 +                        * ask the balancer for the next address and
30375 +                        * check the connection pool if we have a connection open
30376 +                        * for that address
30377 +                        */
30378 +                       if (NULL == (address = proxy_backend_balance(srv, con, sess->proxy_backend))) {
30379 +                               /* we don't have any backends to connect to */
30380 +                               proxy_request *req;
30381 +
30382 +                               /* connection pool is full, queue the request for now */
30383 +                               req = proxy_request_init();
30384 +                               req->added_ts = srv->cur_ts;
30385 +                               req->con = con;
30386 +                               
30387 +                               TRACE("backlog: all backends are down, putting %s (%d) into the backlog", BUF_STR(con->uri.path), con->sock->fd);
30388 +                               proxy_backlog_push(p->conf.backlog, req);
30389 +
30390 +                               /* no, not really a event, 
30391 +                                * we just want to block the outer loop from stepping forward
30392 +                                *
30393 +                                * the trigger will bring this connection back into the game
30394 +                                * */
30395 +                               return HANDLER_WAIT_FOR_EVENT;
30396 +                       }
30397 +
30398 +                       if (PROXY_CONNECTIONPOOL_FULL == proxy_connection_pool_get_connection(
30399 +                                               sess->proxy_backend->pool, 
30400 +                                               address,
30401 +                                               &(sess->proxy_con))) {
30402 +                               proxy_request *req;
30403 +
30404 +                               /* connection pool is full, queue the request for now */
30405 +                               req = proxy_request_init();
30406 +                               req->added_ts = srv->cur_ts;
30407 +                               req->con = con;
30408 +                               
30409 +                               TRACE("backlog: the con-pool is full, putting %s (%d) into the backlog", con->uri.path->ptr, con->sock->fd);
30410 +                               proxy_backlog_push(p->conf.backlog, req);
30411 +
30412 +                               /* no, not really a event, 
30413 +                                * we just want to block the outer loop from stepping forward
30414 +                                *
30415 +                                * the trigger will bring this connection back into the game
30416 +                                * */
30417 +                               return HANDLER_WAIT_FOR_EVENT;
30418 +                       }
30419 +
30420 +                       /* a fresh connection, we need address for it */
30421 +                       if (sess->proxy_con->state == PROXY_CONNECTION_STATE_CONNECTING) {
30422 +                               sess->state = PROXY_STATE_UNSET;
30423 +                               sess->bytes_read = 0;
30424 +                       } else {
30425 +                               /* we are already connected */
30426 +                               sess->state = PROXY_STATE_CONNECTED;
30427 +                               
30428 +                               /* the connection was idling and using the fdevent_idle-handler 
30429 +                                * switch it back to the normal proxy-event-handler */
30430 +                               fdevent_event_del(srv->ev, sess->proxy_con->sock);
30431 +                               fdevent_unregister(srv->ev, sess->proxy_con->sock);
30432 +
30433 +                               fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
30434 +                               fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30435 +                       }
30436 +               }
30437 +
30438 +               switch (proxy_state_engine(srv, con, p, sess)) {
30439 +               case HANDLER_WAIT_FOR_EVENT:
30440 +                       return HANDLER_WAIT_FOR_EVENT;
30441 +               case HANDLER_COMEBACK:
30442 +                       proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30443 +       
30444 +                       fdevent_event_del(srv->ev, sess->proxy_con->sock);
30445 +                       fdevent_unregister(srv->ev, sess->proxy_con->sock);
30446 +
30447 +                       proxy_connection_free(sess->proxy_con);
30448 +
30449 +                       sess->proxy_con = NULL;
30450 +                       /* restart the connection to the backend */
30451 +                       TRACE("%s", "write failed, restarting request");
30452 +                       break;
30453 +               case HANDLER_GO_ON:
30454 +                       return HANDLER_GO_ON;
30455 +               default:
30456 +                       return HANDLER_ERROR;
30457 +               }
30458 +       }
30459 +
30460 +       /* should not be reached */
30461 +       return HANDLER_ERROR;
30462 +}
30463 +
30464 +/**
30465 + * end of the connection to the client
30466 + */
30467 +REQUESTDONE_FUNC(mod_proxy_connection_close_callback) {
30468 +       plugin_data *p = p_d;
30469 +       
30470 +       if (con->mode != p->id) return HANDLER_GO_ON;
30471 +
30472 +       return HANDLER_GO_ON;
30473 +}
30474 +
30475 +/**
30476 + * end of a request
30477 + */
30478 +CONNECTION_FUNC(mod_proxy_connection_reset) {
30479 +       plugin_data *p = p_d;
30480 +       proxy_session *sess = con->plugin_ctx[p->id]; 
30481 +
30482 +       if (con->mode != p->id) return HANDLER_GO_ON;
30483 +
30484 +       if (sess->proxy_con) {
30485 +               switch (sess->proxy_con->state) {
30486 +               case PROXY_CONNECTION_STATE_CONNECTED:
30487 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_IDLE;
30488 +
30489 +                       /* ignore events as the FD is idle, we might get a HUP as the remote connection might close */
30490 +                       fdevent_event_del(srv->ev, sess->proxy_con->sock);
30491 +                       fdevent_unregister(srv->ev, sess->proxy_con->sock);
30492 +
30493 +                       fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent_idle, sess->proxy_con);
30494 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30495 +
30496 +                       break;
30497 +               case PROXY_CONNECTION_STATE_CLOSED:
30498 +                       proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30499 +       
30500 +                       fdevent_event_del(srv->ev, sess->proxy_con->sock);
30501 +                       fdevent_unregister(srv->ev, sess->proxy_con->sock);
30502 +
30503 +                       proxy_connection_free(sess->proxy_con);
30504 +                       break;
30505 +               case PROXY_CONNECTION_STATE_IDLE:
30506 +                       TRACE("%s", "... connection is already back in the pool");
30507 +                       break;
30508 +               default:
30509 +                       ERROR("connection is in a unexpected state at close-time: %d", sess->proxy_con->state);
30510 +                       break;
30511 +               }
30512 +       } else {
30513 +               /* if we have the connection in the backlog, remove it */
30514 +               proxy_backlog_remove_connection(p->conf.backlog, con);
30515 +       }
30516 +       
30517 +
30518 +       proxy_session_free(sess);
30519 +
30520 +       con->plugin_ctx[p->id] = NULL;
30521 +       
30522 +       return HANDLER_GO_ON;
30523 +}
30524 +
30525 +
30526 +
30527 +/**
30528 + * cleanup dead connections once a second
30529 + *
30530 + * the idling event-handler can't cleanup connections itself and has to wait until the 
30531 + * trigger cleans up
30532 + */
30533 +handler_t mod_proxy_trigger_context(server *srv, plugin_config *p) {
30534 +       size_t i, j;
30535 +       proxy_request *req;
30536 +
30537 +       for (i = 0; i < p->backends->used; i++) {
30538 +               proxy_backend *backend = p->backends->ptr[i];
30539 +               proxy_connection_pool *pool = backend->pool;
30540 +               proxy_address_pool *address_pool = backend->address_pool;
30541 +
30542 +               for (j = 0; j < pool->used; ) {
30543 +                       proxy_connection *proxy_con = pool->ptr[j];
30544 +
30545 +                       /* remove-con is removing the current con and moves the good connections to the left
30546 +                        * no need to increment i */
30547 +                       if (proxy_con->state == PROXY_CONNECTION_STATE_CLOSED) {
30548 +                               proxy_connection_pool_remove_connection(backend->pool, proxy_con);
30549 +       
30550 +                               fdevent_event_del(srv->ev, proxy_con->sock);
30551 +                               fdevent_unregister(srv->ev, proxy_con->sock);
30552 +
30553 +                               proxy_connection_free(proxy_con);
30554 +                       } else {
30555 +                               j++;
30556 +                       }
30557 +               }
30558 +
30559 +               /* active the disabled addresses again */
30560 +               for (j = 0; j < address_pool->used; j++) {
30561 +                       proxy_address *address = address_pool->ptr[j];
30562 +
30563 +                       if (address->state != PROXY_ADDRESS_STATE_DISABLED) continue;
30564 +
30565 +                       if (srv->cur_ts > address->disabled_until) {
30566 +                               address->disabled_until = 0;
30567 +                               address->state = PROXY_ADDRESS_STATE_ACTIVE;
30568 +                       }
30569 +               }
30570 +       }
30571 +
30572 +       /* wake up the connections from the backlog */
30573 +       while ((req = proxy_backlog_shift(p->backlog))) {
30574 +               connection *con = req->con;
30575 +
30576 +               joblist_append(srv, con);
30577 +
30578 +               proxy_request_free(req);
30579 +       }
30580 +       
30581 +       return HANDLER_GO_ON;
30582 +}
30583 +
30584 +TRIGGER_FUNC(mod_proxy_trigger) {
30585 +       plugin_data *p = p_d;
30586 +       size_t i;
30587 +       
30588 +       for (i = 0; i < srv->config_context->used; i++) {
30589 +               mod_proxy_trigger_context(srv, p->config_storage[i]);
30590 +       }
30591 +
30592 +       return HANDLER_GO_ON;
30593 +}
30594 +
30595 +int mod_proxy_core_plugin_init(plugin *p) {
30596 +       p->version      = LIGHTTPD_VERSION_ID;
30597 +       p->name         = buffer_init_string("mod_proxy_core");
30598 +
30599 +       p->init         = mod_proxy_core_init;
30600 +       p->cleanup      = mod_proxy_core_free;
30601 +       p->set_defaults = mod_proxy_core_set_defaults;
30602 +       p->handle_uri_clean        = mod_proxy_core_check_extension;
30603 +       p->handle_subrequest_start = mod_proxy_core_check_extension;
30604 +       p->handle_subrequest       = mod_proxy_core_check_extension;
30605 +       p->connection_reset        = mod_proxy_connection_reset;
30606 +       p->handle_connection_close = mod_proxy_connection_close_callback;
30607 +       p->handle_trigger          = mod_proxy_trigger;
30608 +
30609 +       p->data         = NULL;
30610 +
30611 +       return 0;
30612 +}
30613 --- ../lighttpd-1.4.11/src/mod_proxy_core.h     1970-01-01 03:00:00.000000000 +0300
30614 +++ lighttpd-1.4.12/src/mod_proxy_core.h        2006-07-18 13:03:40.000000000 +0300
30615 @@ -0,0 +1,18 @@
30616 +#ifndef _MOD_PROXY_CORE_H_
30617 +#define _MOD_PROXY_CORE_H_
30618 +
30619 +#include "buffer.h"
30620 +#include "base.h"
30621 +
30622 +#define PROXY_BACKEND_CONNECT_PARAMS \
30623 +       (server *srv, connection *con, void *p_d)
30624 +
30625 +#define PROXY_BACKEND_CONNECT_RETVAL handler_t
30626 +
30627 +#define PROXY_BACKEND_CONNECT(name) \
30628 +       PROXY_BACKEND_CONNECT_RETVAL name PROXY_BACKEND_CONNECT_PARAMS
30629 +
30630 +#define PROXY_BACKEND_CONNECT_PTR(name) \
30631 +       PROXY_BACKEND_CONNECT_RETVAL (* name)PROXY_BACKEND_CONNECT_PARAMS
30632 +
30633 +#endif
30634 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.c     1970-01-01 03:00:00.000000000 +0300
30635 +++ lighttpd-1.4.12/src/mod_proxy_core_address.c        2006-07-20 00:57:20.000000000 +0300
30636 @@ -0,0 +1,186 @@
30637 +#include <stdlib.h>
30638 +#include <string.h>
30639 +
30640 +#include "log.h"
30641 +#include "sys-socket.h"
30642 +#include "mod_proxy_core_address.h"
30643 +
30644 +proxy_address *proxy_address_init(void) {
30645 +       proxy_address *address;
30646 +
30647 +       address = calloc(1, sizeof(*address));
30648 +
30649 +       address->name = buffer_init();
30650 +
30651 +       return address;
30652 +}
30653 +
30654 +void proxy_address_free(proxy_address *address) {
30655 +       if (!address) return;
30656 +
30657 +       buffer_free(address->name);
30658 +
30659 +       free(address);
30660 +}
30661 +
30662 +
30663 +proxy_address_pool *proxy_address_pool_init(void) {
30664 +       proxy_address_pool *address_pool;
30665 +
30666 +       address_pool = calloc(1, sizeof(*address_pool));
30667 +
30668 +       return address_pool;
30669 +}
30670 +
30671 +void proxy_address_pool_free(proxy_address_pool *address_pool) {
30672 +       if (!address_pool) return;
30673 +
30674 +       FOREACH(address_pool, element, proxy_address_free(element));
30675 +
30676 +       if (address_pool->ptr) free(address_pool->ptr);
30677 +
30678 +       free(address_pool);
30679 +}
30680 +
30681 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address) {
30682 +       size_t i;
30683 +
30684 +       /* check if this address is already known */
30685 +
30686 +       for (i = 0; i < address_pool->used; i++) {
30687 +               proxy_address *pool_address = address_pool->ptr[i];
30688 +
30689 +               if (buffer_is_equal(address->name, pool_address->name)) {
30690 +                       TRACE("%s is already in the address-pool", BUF_STR(address->name));
30691 +
30692 +                       proxy_address_free(address);
30693 +
30694 +                       return;
30695 +               }       
30696 +       }
30697 +
30698 +       TRACE("adding %s to the address-pool", BUF_STR(address->name));
30699 +
30700 +       ARRAY_STATIC_PREPARE_APPEND(address_pool);
30701 +
30702 +       address_pool->ptr[address_pool->used++] = address;
30703 +}
30704 +
30705 +int  proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *name) {
30706 +       struct addrinfo *res = NULL, pref, *cur;
30707 +       int ret;
30708 +       buffer *hostname = NULL, *port = NULL;
30709 +       char *colon;
30710 +
30711 +       pref.ai_flags = 0;
30712 +       pref.ai_family = PF_UNSPEC;
30713 +       pref.ai_socktype = SOCK_STREAM;
30714 +       pref.ai_protocol = 0;
30715 +       pref.ai_addrlen = 0;
30716 +       pref.ai_addr = NULL;
30717 +       pref.ai_canonname = NULL;
30718 +       pref.ai_next = NULL;
30719 +
30720 +       /* check the address style
30721 +        *
30722 +        * unix:/tmp/socket
30723 +        * www.example.org
30724 +        * www.example.org:80
30725 +        * 127.0.0.1
30726 +        * 127.0.0.1:80
30727 +        * [::1]:80
30728 +        * [::1]
30729 +        */
30730 +
30731 +       if (buffer_is_empty(name)) return -1;
30732 +
30733 +       if (0 == strncmp(BUF_STR(name), "unix:", 5)) {
30734 +               /* a unix domain socket */
30735 +               ERROR("unix: scheme is not supported for %s", BUF_STR(name));
30736 +               return -1;
30737 +       } else if (name->ptr[0] == '[') {
30738 +               if (name->ptr[name->used - 1] == ']') {
30739 +                       /* no port-number attached */
30740 +               
30741 +                       hostname = buffer_init();
30742 +                       buffer_copy_string_len(hostname, BUF_STR(name) + 1, name->used - 3);
30743 +                       port = buffer_init_string("80");
30744 +               } else if (NULL != (colon = strrchr(BUF_STR(name), ':'))) {
30745 +                       /* with port number */
30746 +
30747 +                       hostname = buffer_init();
30748 +                       buffer_copy_string_len(hostname, BUF_STR(name) + 1, colon - BUF_STR(name) - 2);
30749 +                       port = buffer_init();
30750 +                       buffer_copy_string(port, colon + 1);
30751 +
30752 +               } else {
30753 +                       ERROR("this is neither [<ipv6-address>] nor [<ipv6-address>]:<port>: %s", BUF_STR(name));
30754 +
30755 +                       return -1;
30756 +               }
30757 +       } else if (name->ptr[name->used - 1] != ']' &&
30758 +                  NULL != (colon = strrchr(BUF_STR(name), ':'))) {
30759 +
30760 +               hostname = buffer_init();
30761 +               buffer_copy_string_len(hostname, BUF_STR(name), colon - BUF_STR(name));
30762 +               port = buffer_init();
30763 +               buffer_copy_string(port, colon + 1);
30764 +       } else {
30765 +               /* no colon, just a IPv4 address or a domain name */
30766 +
30767 +               hostname = buffer_init_string(BUF_STR(name));
30768 +               port = buffer_init_string("80");
30769 +       }
30770 +
30771 +       TRACE("resolving %s on port %s", BUF_STR(hostname), BUF_STR(port));
30772 +       
30773 +       if (0 != (ret = getaddrinfo(BUF_STR(hostname), BUF_STR(port), &pref, &res))) {
30774 +               ERROR("getaddrinfo failed: %s", gai_strerror(ret));
30775 +
30776 +               buffer_free(hostname);
30777 +               buffer_free(port);
30778 +
30779 +               return -1;
30780 +       }
30781 +
30782 +       buffer_free(hostname);
30783 +       buffer_free(port);
30784 +
30785 +       for (cur = res; cur; cur = cur->ai_next) {
30786 +               proxy_address *a = proxy_address_init();
30787 +
30788 +               memcpy(&(a->addr), cur->ai_addr, cur->ai_addrlen);
30789 +
30790 +               a->state = PROXY_ADDRESS_STATE_ACTIVE;
30791 +               buffer_prepare_copy(a->name, 128);
30792 +
30793 +               switch (cur->ai_family) {
30794 +               case AF_INET6:
30795 +                       a->name->ptr[0] = '[';
30796 +                       inet_ntop(cur->ai_family, &(a->addr.ipv6.sin6_addr), a->name->ptr + 1, a->name->size - 2);
30797 +                       a->name->used = strlen(a->name->ptr) + 1;
30798 +                       buffer_append_string(a->name, "]:");
30799 +                       buffer_append_long(a->name, ntohs(a->addr.ipv6.sin6_port));
30800 +                       break;
30801 +               case AF_INET:
30802 +                       inet_ntop(cur->ai_family, &(a->addr.ipv4.sin_addr), a->name->ptr, a->name->size - 1);
30803 +                       a->name->used = strlen(a->name->ptr) + 1;
30804 +
30805 +                       buffer_append_string(a->name, ":");
30806 +                       buffer_append_long(a->name, ntohs(a->addr.ipv4.sin_port));
30807 +                       break;
30808 +               default:
30809 +                       ERROR("unknown address-family: %d", cur->ai_family);
30810 +                       return -1;
30811 +               }
30812 +
30813 +
30814 +               proxy_address_pool_add(address_pool, a);
30815 +       }
30816 +
30817 +       freeaddrinfo(res);
30818 +
30819 +       return 0;
30820 +}
30821 +
30822 +
30823 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.h     1970-01-01 03:00:00.000000000 +0300
30824 +++ lighttpd-1.4.12/src/mod_proxy_core_address.h        2006-07-18 13:03:40.000000000 +0300
30825 @@ -0,0 +1,33 @@
30826 +#ifndef _MOD_PROXY_CORE_ADDRESS_H_
30827 +#define _MOD_PROXY_CORE_ADDRESS_H_
30828 +
30829 +#include <time.h>
30830 +#include "buffer.h"
30831 +#include "sys-socket.h"
30832 +#include "array-static.h"
30833 +
30834 +typedef enum {
30835 +       PROXY_ADDRESS_STATE_UNSET,
30836 +       PROXY_ADDRESS_STATE_ACTIVE,
30837 +       PROXY_ADDRESS_STATE_DISABLED,
30838 +} proxy_address_state_t;
30839 +
30840 +typedef struct {
30841 +       sock_addr addr;
30842 +
30843 +       buffer *name; /* a inet_ntoa() prepresentation of the address */
30844 +
30845 +       time_t last_used;
30846 +       time_t disabled_until;
30847 +
30848 +       proxy_address_state_t state;
30849 +} proxy_address;
30850 +
30851 +ARRAY_STATIC_DEF(proxy_address_pool, proxy_address, );
30852 +
30853 +proxy_address_pool *proxy_address_pool_init(void); 
30854 +void proxy_address_pool_free(proxy_address_pool *address_pool); 
30855 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address);
30856 +int proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *address);
30857 +
30858 +#endif
30859 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.c     1970-01-01 03:00:00.000000000 +0300
30860 +++ lighttpd-1.4.12/src/mod_proxy_core_backend.c        2006-07-20 00:57:19.000000000 +0300
30861 @@ -0,0 +1,47 @@
30862 +#include <stdlib.h>
30863 +
30864 +#include "mod_proxy_core_backend.h"
30865 +#include "mod_proxy_core_pool.h"
30866 +#include "mod_proxy_core_address.h"
30867 +
30868 +proxy_backend *proxy_backend_init(void) {
30869 +       proxy_backend *backend;
30870 +
30871 +       backend = calloc(1, sizeof(*backend));
30872 +       backend->pool = proxy_connection_pool_init();
30873 +       backend->address_pool = proxy_address_pool_init();
30874 +       backend->balancer = PROXY_BALANCE_RR;
30875 +
30876 +       return backend;
30877 +}
30878 +
30879 +void proxy_backend_free(proxy_backend *backend) {
30880 +       if (!backend) return;
30881 +
30882 +       proxy_address_pool_free(backend->address_pool);
30883 +       proxy_connection_pool_free(backend->pool);
30884 +       
30885 +       free(backend);
30886 +}
30887 +
30888 +proxy_backends *proxy_backends_init(void) {
30889 +       proxy_backends *backends;
30890 +
30891 +       backends = calloc(1, sizeof(*backends));
30892 +
30893 +       return backends;
30894 +}
30895 +
30896 +void proxy_backends_free(proxy_backends *backends) {
30897 +       FOREACH(backends, element, proxy_backend_free(element))
30898 +
30899 +       if (backends->ptr) free(backends->ptr);
30900 +
30901 +       free(backends);
30902 +}
30903 +
30904 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend) {
30905 +       ARRAY_STATIC_PREPARE_APPEND(backends);
30906 +
30907 +       backends->ptr[backends->used++] = backend;
30908 +}
30909 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.h     1970-01-01 03:00:00.000000000 +0300
30910 +++ lighttpd-1.4.12/src/mod_proxy_core_backend.h        2006-07-18 13:03:40.000000000 +0300
30911 @@ -0,0 +1,54 @@
30912 +#ifndef _MOD_PROXY_CORE_BACKEND_H_
30913 +#define _MOD_PROXY_CORE_BACKEND_H_
30914 +
30915 +#include "array-static.h"
30916 +#include "buffer.h"
30917 +#include "mod_proxy_core_address.h"
30918 +#include "mod_proxy_core_pool.h"
30919 +#include "sys-socket.h"
30920 +
30921 +/**
30922 + * a single DNS name might explode to several IP addresses 
30923 + * 
30924 + * url: 
30925 + * - http://foo.bar/suburl/
30926 + * - https://foo.bar/suburl/
30927 + * - unix:/tmp/socket
30928 + * - tcp://foobar:1025/
30929 + *
30930 + * backend:
30931 + * - scgi
30932 + * - http
30933 + * - fastcgi
30934 + *
30935 + * request-url-rewrite
30936 + * response-url-rewrite
30937 + */ 
30938 +typedef enum {
30939 +       PROXY_BALANCE_UNSET,
30940 +       PROXY_BALANCE_FAIR,
30941 +       PROXY_BALANCE_HASH,
30942 +       PROXY_BALANCE_RR
30943 +} proxy_balance_t;
30944 +
30945 +typedef struct {
30946 +       buffer *url;
30947 +
30948 +       proxy_connection_pool *pool;  /* pool of active connections */
30949 +       int use_keepalive;
30950 +
30951 +       proxy_address_pool *address_pool; /* possible destination-addresses, disabling is done here */
30952 +       proxy_balance_t balancer; /* how to choose a address from the address-pool */
30953 +} proxy_backend;
30954 +
30955 +ARRAY_STATIC_DEF(proxy_backends, proxy_backend, );
30956 +
30957 +proxy_backend *proxy_backend_init(void);
30958 +void proxy_backend_free(proxy_backend *backend);
30959 +
30960 +proxy_backends *proxy_backends_init(void);
30961 +void proxy_backends_free(proxy_backends *backends);
30962 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend);
30963 +
30964 +#endif
30965 +
30966 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.c     1970-01-01 03:00:00.000000000 +0300
30967 +++ lighttpd-1.4.12/src/mod_proxy_core_backlog.c        2006-07-18 13:03:40.000000000 +0300
30968 @@ -0,0 +1,109 @@
30969 +#include <stdlib.h>
30970 +
30971 +#include "mod_proxy_core_backlog.h"
30972 +#include "array-static.h"
30973 +
30974 +proxy_backlog *proxy_backlog_init(void) {
30975 +       STRUCT_INIT(proxy_backlog, backlog);
30976 +
30977 +       return backlog;
30978 +}
30979 +
30980 +void proxy_backlog_free(proxy_backlog *backlog) {
30981 +       if (!backlog) return;
30982 +
30983 +       free(backlog);
30984 +}
30985 +
30986 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req) {
30987 +       /* first entry */
30988 +       if (NULL == backlog->first) {
30989 +               backlog->first = backlog->last = req;
30990 +       } else {
30991 +               backlog->last->next = req;
30992 +               backlog->last = req;
30993 +       }
30994 +       backlog->length++;
30995 +
30996 +       return 0;
30997 +}
30998 +
30999 +/**
31000 + * remove the first element from the backlog
31001 + */
31002 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog) {
31003 +       proxy_request *req = NULL;
31004 +
31005 +       if (!backlog->first) return req;
31006 +
31007 +       backlog->length--;
31008 +
31009 +       req = backlog->first;
31010 +
31011 +       backlog->first = req->next;
31012 +
31013 +       /* the backlog is empty */
31014 +       if (backlog->first == NULL) backlog->last = NULL;
31015 +
31016 +       return req;
31017 +}
31018 +
31019 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con) {
31020 +       proxy_request *req = NULL;
31021 +
31022 +       if (!backlog->first) return -1;
31023 +       if (!con) return -1;
31024 +
31025 +       /* the first element is what we look for */
31026 +       if (backlog->first->con == con) {
31027 +               req = backlog->first;
31028 +               
31029 +               backlog->first = req->next;
31030 +               if (backlog->first == NULL) backlog->last = NULL;
31031 +
31032 +               backlog->length--;
31033 +               
31034 +               proxy_request_free(req);
31035 +
31036 +               return 0;
31037 +       }
31038 +
31039 +
31040 +       for (req = backlog->first; req && req->next; req = req->next) {
31041 +               proxy_request *cur;
31042 +
31043 +               if (req->next->con != con) continue;
31044 +
31045 +               backlog->length--;
31046 +               /* the next node is our searched connection */
31047 +
31048 +               cur = req->next;
31049 +               req->next = cur->next;
31050 +
31051 +               /* the next node is the last one, make the current the new last */
31052 +               if (cur == backlog->last) {
31053 +                       backlog->last = req;
31054 +               }
31055 +               cur->next = NULL;
31056 +
31057 +               proxy_request_free(req);
31058 +
31059 +               return 0;
31060 +       }
31061 +
31062 +       return -1;
31063 +}
31064 +
31065 +proxy_request *proxy_request_init(void) {
31066 +       STRUCT_INIT(proxy_request, request);
31067 +
31068 +       return request;
31069 +}
31070 +
31071 +void proxy_request_free(proxy_request *request) {
31072 +       if (!request) return;
31073 +
31074 +       free(request);
31075 +}
31076 +
31077 +
31078 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.h     1970-01-01 03:00:00.000000000 +0300
31079 +++ lighttpd-1.4.12/src/mod_proxy_core_backlog.h        2006-07-18 13:03:40.000000000 +0300
31080 @@ -0,0 +1,56 @@
31081 +#ifndef _MOD_PROXY_CORE_BACKLOG_H_
31082 +#define _MOD_PROXY_CORE_BACKLOG_H_
31083 +
31084 +#include <sys/types.h>
31085 +#include <sys/time.h>
31086 +
31087 +typedef struct _proxy_request {
31088 +       void *con; /* a pointer to the client-connection, (type: connection) */
31089 +
31090 +       time_t added_ts; /* when was the entry added (for timeout handling) */
31091 +
31092 +       struct _proxy_request *next;
31093 +} proxy_request;
31094 +
31095 +/**
31096 + * a we can't get a connection from the pool, queue the request in the
31097 + * request queue (FIFO)
31098 + *
31099 + * - the queue is infinite
31100 + * - entries are removed after a timeout (status 504)
31101 + */
31102 +typedef struct {
31103 +       proxy_request *first; /* pull() does q->first = q->first->next */
31104 +       proxy_request *last; /* push() does q->last = r */
31105 +
31106 +       size_t length;
31107 +} proxy_backlog;
31108 +
31109 +proxy_backlog *proxy_backlog_init(void);
31110 +void proxy_backlog_free(proxy_backlog *backlog);
31111 +
31112 +/**
31113 + * append a request to the end
31114 + * 
31115 + * @return 0 in success, -1 if full
31116 + */ 
31117 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req);
31118 +
31119 +/**
31120 + * remove the first request from the backlog
31121 + *
31122 + * @return NULL if backlog is empty, the request otherwise
31123 + */
31124 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog);
31125 +/**
31126 + * remove the request with the connection 'con' from the backlog
31127 + *
31128 + * @return -1 if not found, 0 otherwise
31129 + */
31130 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con);
31131 +
31132 +proxy_request *proxy_request_init(void);
31133 +void proxy_request_free(proxy_request *req);
31134 +
31135 +#endif
31136 +
31137 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.c        1970-01-01 03:00:00.000000000 +0300
31138 +++ lighttpd-1.4.12/src/mod_proxy_core_pool.c   2006-07-18 13:03:40.000000000 +0300
31139 @@ -0,0 +1,127 @@
31140 +
31141 +#include <stdlib.h>
31142 +
31143 +#include "array-static.h"
31144 +#include "sys-files.h"
31145 +#include "log.h"
31146 +#include "mod_proxy_core_pool.h"
31147 +
31148 +proxy_connection * proxy_connection_init(void) {
31149 +       proxy_connection *con;
31150 +
31151 +       con = calloc(1, sizeof(*con));
31152 +
31153 +       con->sock = iosocket_init();
31154 +
31155 +       return con;
31156 +}
31157 +
31158 +void proxy_connection_free(proxy_connection *con) {
31159 +       if (!con) return;
31160 +
31161 +       iosocket_free(con->sock);
31162 +
31163 +       free(con);
31164 +}
31165 +
31166 +proxy_connection_pool *proxy_connection_pool_init(void) {
31167 +       proxy_connection_pool *pool;
31168 +
31169 +       pool = calloc(1, sizeof(*pool));
31170 +
31171 +               /* default: max parallel connections to the backend
31172 +        * 
31173 +        * this should match max-procs if we manage the procs ourself
31174 +                */
31175 +
31176 +       pool->max_size = 8;
31177 +
31178 +       return pool;
31179 +}
31180 +
31181 +void proxy_connection_pool_free(proxy_connection_pool *pool) {
31182 +       size_t i;
31183 +
31184 +       if (!pool) return;
31185 +
31186 +       for (i = 0; i < pool->used; i++) {
31187 +               proxy_connection_free(pool->ptr[i]);
31188 +       }
31189 +
31190 +       if (pool->size) free(pool->ptr);
31191 +
31192 +       free(pool);
31193 +}
31194 +
31195 +void proxy_connection_pool_add_connection(proxy_connection_pool *pool, proxy_connection *c) {
31196 +       ARRAY_STATIC_PREPARE_APPEND(pool);
31197 +
31198 +       pool->ptr[pool->used++] = c;
31199 +}
31200 +/**
31201 + * remove the connection from the pool
31202 + *
31203 + * usually called on conn-shutdown
31204 + */
31205 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c) {
31206 +       size_t i;
31207 +
31208 +       if (pool->used == 0) return -1; /* empty */
31209 +
31210 +       for (i = 0; i < pool->used; i++) {
31211 +               if (pool->ptr[i] == c) {
31212 +                       break;
31213 +               }
31214 +       }
31215 +
31216 +       if (i == pool->used) return -1; /* not found */
31217 +
31218 +       /**
31219 +        * move all elements one to the left
31220 +        *
31221 +        * if the last element is going to be removed, skip the loop
31222 +        */
31223 +       for (; i < pool->used - 1; i++) {
31224 +               pool->ptr[i] = pool->ptr[i + 1];
31225 +       }
31226 +
31227 +       pool->used--;
31228 +
31229 +       return 0;
31230 +}
31231 +
31232 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon) {
31233 +       proxy_connection *proxy_con = NULL;
31234 +       size_t i;
31235 +
31236 +       /* search for a idling proxy connection with the given address */
31237 +       for (i = 0; i < pool->used; i++) {
31238 +               proxy_con = pool->ptr[i];
31239 +
31240 +               if (proxy_con->address == address &&
31241 +                   proxy_con->state == PROXY_CONNECTION_STATE_IDLE) {
31242 +                       break;
31243 +               }
31244 +       }
31245 +
31246 +       if (i == pool->used) {
31247 +               /* no idling connection found */
31248 +
31249 +               if (pool->used == pool->max_size) return PROXY_CONNECTIONPOOL_FULL;
31250 +               
31251 +               proxy_con = proxy_connection_init();
31252 +
31253 +               proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
31254 +               proxy_con->address = address;
31255 +
31256 +               proxy_connection_pool_add_connection(pool, proxy_con);
31257 +       } else {
31258 +               proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
31259 +       }
31260 +
31261 +       *rcon = proxy_con;
31262 +
31263 +       return PROXY_CONNECTIONPOOL_GOT_CONNECTION;
31264 +}
31265 +
31266 +
31267 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.h        1970-01-01 03:00:00.000000000 +0300
31268 +++ lighttpd-1.4.12/src/mod_proxy_core_pool.h   2006-07-18 13:03:40.000000000 +0300
31269 @@ -0,0 +1,52 @@
31270 +#ifndef _MOD_PROXY_CORE_POOL_H_
31271 +#define _MOD_PROXY_CORE_POOL_H_
31272 +
31273 +#include <sys/time.h>
31274 +
31275 +#include "iosocket.h"
31276 +#include "array-static.h"
31277 +#include "mod_proxy_core_address.h"
31278 +
31279 +typedef enum {
31280 +       PROXY_CONNECTION_STATE_UNSET,
31281 +       PROXY_CONNECTION_STATE_CONNECTING,
31282 +       PROXY_CONNECTION_STATE_CONNECTED,
31283 +       PROXY_CONNECTION_STATE_IDLE,
31284 +       PROXY_CONNECTION_STATE_CLOSED,
31285 +} proxy_connection_state_t;
31286 +
31287 +/**
31288 + * a connection to a proxy backend
31289 + * 
31290 + * the connection is independent of the incoming request to allow keep-alive
31291 + */
31292 +typedef struct { 
31293 +       iosocket *sock;
31294 +
31295 +       time_t last_read; /* timeout handling for keep-alive connections */
31296 +       time_t last_write;
31297 +
31298 +       proxy_address *address; /* the struct sock_addr for the sock */
31299 +
31300 +       proxy_connection_state_t state;
31301 +} proxy_connection;
31302 +
31303 +ARRAY_STATIC_DEF(proxy_connection_pool, proxy_connection, size_t max_size;);
31304 +
31305 +typedef enum {
31306 +       PROXY_CONNECTIONPOOL_UNSET,
31307 +       PROXY_CONNECTIONPOOL_FULL,
31308 +       PROXY_CONNECTIONPOOL_GOT_CONNECTION,
31309 +} proxy_connection_pool_t;
31310 +
31311 +proxy_connection_pool *proxy_connection_pool_init(void); 
31312 +void proxy_connection_pool_free(proxy_connection_pool *pool); 
31313 +
31314 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon);
31315 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c);
31316 +
31317 +proxy_connection * proxy_connection_init(void);
31318 +void proxy_connection_free(proxy_connection *pool);
31319 +
31320 +#endif
31321 +
31322 --- ../lighttpd-1.4.11/src/mod_proxy_core_rewrites.c    1970-01-01 03:00:00.000000000 +0300
31323 +++ lighttpd-1.4.12/src/mod_proxy_core_rewrites.c       2006-07-18 17:34:32.000000000 +0300
31324 @@ -0,0 +1,64 @@
31325 +#include <stdlib.h>
31326 +#include <string.h>
31327 +
31328 +#include "mod_proxy_core_rewrites.h"
31329 +#include "log.h"
31330 +
31331 +proxy_rewrite *proxy_rewrite_init(void) {
31332 +       STRUCT_INIT(proxy_rewrite, rewrite);
31333 +
31334 +       rewrite->header = buffer_init();
31335 +       rewrite->match = buffer_init();
31336 +       rewrite->replace = buffer_init();
31337 +
31338 +       return rewrite;
31339 +
31340 +}
31341 +void proxy_rewrite_free(proxy_rewrite *rewrite) {
31342 +       if (!rewrite) return;
31343 +
31344 +       if (rewrite->regex) pcre_free(rewrite->regex);
31345 +
31346 +       buffer_free(rewrite->header);
31347 +       buffer_free(rewrite->match);
31348 +       buffer_free(rewrite->replace);
31349 +
31350 +       free(rewrite);
31351 +}
31352 +
31353 +int proxy_rewrite_set_regex(proxy_rewrite *rewrite, buffer *regex) {
31354 +       const char *errptr;
31355 +       int erroff;
31356 +
31357 +       if (NULL == (rewrite->regex = pcre_compile(BUF_STR(regex),
31358 +                 0, &errptr, &erroff, NULL))) {
31359 +               
31360 +               TRACE("regex compilation for %s failed at %s", BUF_STR(regex), errptr);
31361 +
31362 +               return -1;
31363 +       }
31364 +
31365 +       return 0;
31366 +}
31367 +
31368 +
31369 +proxy_rewrites *proxy_rewrites_init(void) {
31370 +       STRUCT_INIT(proxy_rewrites, rewrites);
31371 +
31372 +       return rewrites;
31373 +}
31374 +
31375 +void proxy_rewrites_add(proxy_rewrites *rewrites, proxy_rewrite *rewrite) {
31376 +       ARRAY_STATIC_PREPARE_APPEND(rewrites);
31377 +
31378 +       rewrites->ptr[rewrites->used++] = rewrite;
31379 +}
31380 +
31381 +void proxy_rewrites_free(proxy_rewrites *rewrites) {
31382 +       if (!rewrites) return;
31383 +
31384 +       free(rewrites);
31385 +}
31386 +
31387 +
31388 +
31389 --- ../lighttpd-1.4.11/src/mod_proxy_core_rewrites.h    1970-01-01 03:00:00.000000000 +0300
31390 +++ lighttpd-1.4.12/src/mod_proxy_core_rewrites.h       2006-07-18 17:34:32.000000000 +0300
31391 @@ -0,0 +1,28 @@
31392 +#ifndef _MOD_PROXY_CORE_REWRITES_H_
31393 +#define _MOD_PROXY_CORE_REWRITES_H_
31394 +
31395 +#include <pcre.h>
31396 +#include "array-static.h"
31397 +#include "buffer.h"
31398 +
31399 +typedef struct {
31400 +       buffer *header;
31401 +
31402 +       pcre *regex; /* regex compiled from the <match> */
31403 +
31404 +       buffer *match;
31405 +       buffer *replace;
31406 +} proxy_rewrite;
31407 +
31408 +ARRAY_STATIC_DEF(proxy_rewrites, proxy_rewrite,);
31409 +
31410 +proxy_rewrite *proxy_rewrite_init(void);
31411 +void proxy_rewrite_free(proxy_rewrite *rewrite);
31412 +int proxy_rewrite_set_regex(proxy_rewrite *rewrite, buffer *regex);
31413 +
31414 +proxy_rewrites *proxy_rewrites_init(void);
31415 +void proxy_rewrites_add(proxy_rewrites *rewrites, proxy_rewrite *rewrite);
31416 +void proxy_rewrites_free(proxy_rewrites *rewrites);
31417 +
31418 +#endif
31419 +
31420 --- ../lighttpd-1.4.11/src/mod_redirect.c       2006-02-08 15:38:06.000000000 +0200
31421 +++ lighttpd-1.4.12/src/mod_redirect.c  2006-07-16 00:26:04.000000000 +0300
31422 @@ -22,35 +22,35 @@
31423         PLUGIN_DATA;
31424         buffer *match_buf;
31425         buffer *location;
31426 -       
31427 +
31428         plugin_config **config_storage;
31429 -       
31430 -       plugin_config conf; 
31431 +
31432 +       plugin_config conf;
31433  } plugin_data;
31434  
31435  INIT_FUNC(mod_redirect_init) {
31436         plugin_data *p;
31437 -       
31438 +
31439         p = calloc(1, sizeof(*p));
31440 -       
31441 +
31442         p->match_buf = buffer_init();
31443         p->location = buffer_init();
31444 -       
31445 +
31446         return p;
31447  }
31448  
31449  FREE_FUNC(mod_redirect_free) {
31450         plugin_data *p = p_d;
31451 -       
31452 +
31453         if (!p) return HANDLER_GO_ON;
31454  
31455         if (p->config_storage) {
31456                 size_t i;
31457                 for (i = 0; i < srv->config_context->used; i++) {
31458                         plugin_config *s = p->config_storage[i];
31459 -                       
31460 +
31461                         pcre_keyvalue_buffer_free(s->redirect);
31462 -                       
31463 +
31464                         free(s);
31465                 }
31466                 free(p->config_storage);
31467 @@ -59,9 +59,9 @@
31468  
31469         buffer_free(p->match_buf);
31470         buffer_free(p->location);
31471 -       
31472 +
31473         free(p);
31474 -       
31475 +
31476         return HANDLER_GO_ON;
31477  }
31478  
31479 @@ -69,195 +69,137 @@
31480         plugin_data *p = p_d;
31481         data_unset *du;
31482         size_t i = 0;
31483 -       
31484 -       config_values_t cv[] = { 
31485 +
31486 +       config_values_t cv[] = {
31487                 { "url.redirect",               NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
31488                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
31489         };
31490 -       
31491 +
31492         if (!p) return HANDLER_ERROR;
31493 -       
31494 +
31495         /* 0 */
31496         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
31497 -       
31498 +
31499         for (i = 0; i < srv->config_context->used; i++) {
31500                 plugin_config *s;
31501                 size_t j;
31502                 array *ca;
31503                 data_array *da = (data_array *)du;
31504 -               
31505 +
31506                 s = calloc(1, sizeof(plugin_config));
31507                 s->redirect   = pcre_keyvalue_buffer_init();
31508 -               
31509 +
31510                 cv[0].destination = s->redirect;
31511 -               
31512 +
31513                 p->config_storage[i] = s;
31514                 ca = ((data_config *)srv->config_context->data[i])->value;
31515 -       
31516 +
31517                 if (0 != config_insert_values_global(srv, ca, cv)) {
31518                         return HANDLER_ERROR;
31519                 }
31520 -               
31521 +
31522                 if (NULL == (du = array_get_element(ca, "url.redirect"))) {
31523                         /* no url.redirect defined */
31524                         continue;
31525                 }
31526 -               
31527 +
31528                 if (du->type != TYPE_ARRAY) {
31529 -                       log_error_write(srv, __FILE__, __LINE__, "sss", 
31530 +                       log_error_write(srv, __FILE__, __LINE__, "sss",
31531                                         "unexpected type for key: ", "url.redirect", "array of strings");
31532 -                       
31533 +
31534                         return HANDLER_ERROR;
31535                 }
31536 -               
31537 +
31538                 da = (data_array *)du;
31539 -                               
31540 +
31541                 for (j = 0; j < da->value->used; j++) {
31542                         if (da->value->data[j]->type != TYPE_STRING) {
31543 -                               log_error_write(srv, __FILE__, __LINE__, "sssbs", 
31544 -                                               "unexpected type for key: ", 
31545 -                                               "url.redirect", 
31546 +                               log_error_write(srv, __FILE__, __LINE__, "sssbs",
31547 +                                               "unexpected type for key: ",
31548 +                                               "url.redirect",
31549                                                 "[", da->value->data[j]->key, "](string)");
31550 -                               
31551 +
31552                                 return HANDLER_ERROR;
31553                         }
31554 -                               
31555 -                       if (0 != pcre_keyvalue_buffer_append(s->redirect, 
31556 +
31557 +                       if (0 != pcre_keyvalue_buffer_append(s->redirect,
31558                                                              ((data_string *)(da->value->data[j]))->key->ptr,
31559                                                              ((data_string *)(da->value->data[j]))->value->ptr)) {
31560 -                                       
31561 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
31562 +
31563 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
31564                                                 "pcre-compile failed for", da->value->data[j]->key);
31565                         }
31566                 }
31567         }
31568 -       
31569 +
31570         return HANDLER_GO_ON;
31571  }
31572  #ifdef HAVE_PCRE_H
31573  static int mod_redirect_patch_connection(server *srv, connection *con, plugin_data *p) {
31574         size_t i, j;
31575         plugin_config *s = p->config_storage[0];
31576 -       
31577 +
31578         p->conf.redirect = s->redirect;
31579 -       
31580 +
31581         /* skip the first, the global context */
31582         for (i = 1; i < srv->config_context->used; i++) {
31583                 data_config *dc = (data_config *)srv->config_context->data[i];
31584                 s = p->config_storage[i];
31585 -               
31586 +
31587                 /* condition didn't match */
31588                 if (!config_check_cond(srv, con, dc)) continue;
31589 -               
31590 +
31591                 /* merge config */
31592                 for (j = 0; j < dc->value->used; j++) {
31593                         data_unset *du = dc->value->data[j];
31594 -                       
31595 +
31596                         if (0 == strcmp(du->key->ptr, "url.redirect")) {
31597                                 p->conf.redirect = s->redirect;
31598                                 p->conf.context = dc;
31599                         }
31600                 }
31601         }
31602 -       
31603 +
31604         return 0;
31605  }
31606  #endif
31607  static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_data) {
31608  #ifdef HAVE_PCRE_H
31609         plugin_data *p = p_data;
31610 -       size_t i;
31611 +       int i;
31612  
31613 -       /* 
31614 +       /*
31615          * REWRITE URL
31616 -        * 
31617 +        *
31618          * e.g. redirect /base/ to /index.php?section=base
31619 -        * 
31620 +        *
31621          */
31622 -       
31623 +
31624         mod_redirect_patch_connection(srv, con, p);
31625 -       
31626 +
31627         buffer_copy_string_buffer(p->match_buf, con->request.uri);
31628 -       
31629 -       for (i = 0; i < p->conf.redirect->used; i++) {
31630 -               pcre *match;
31631 -               pcre_extra *extra;
31632 -               const char *pattern;
31633 -               size_t pattern_len;
31634 -               int n;
31635 -               pcre_keyvalue *kv = p->conf.redirect->kv[i];
31636 -# define N 10
31637 -               int ovec[N * 3];
31638 -               
31639 -               match       = kv->key;
31640 -               extra       = kv->key_extra;
31641 -               pattern     = kv->value->ptr;
31642 -               pattern_len = kv->value->used - 1;
31643 -               
31644 -               if ((n = pcre_exec(match, extra, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
31645 -                       if (n != PCRE_ERROR_NOMATCH) {
31646 -                               log_error_write(srv, __FILE__, __LINE__, "sd",
31647 -                                               "execution error while matching: ", n);
31648 -                               return HANDLER_ERROR;
31649 -                       }
31650 -               } else {
31651 -                       const char **list;
31652 -                       size_t start, end;
31653 -                       size_t k;
31654 -                       
31655 -                       /* it matched */
31656 -                       pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
31657 -                       
31658 -                       /* search for $[0-9] */
31659 -                       
31660 -                       buffer_reset(p->location);
31661 -                       
31662 -                       start = 0; end = pattern_len;
31663 -                       for (k = 0; k < pattern_len; k++) {
31664 -                               if ((pattern[k] == '$' || pattern[k] == '%') &&
31665 -                                   isdigit((unsigned char)pattern[k + 1])) {
31666 -                                       /* got one */
31667 -                                       
31668 -                                       size_t num = pattern[k + 1] - '0';
31669 -                                       
31670 -                                       end = k;
31671 -                                       
31672 -                                       buffer_append_string_len(p->location, pattern + start, end - start);
31673 -                                       
31674 -                                       if (pattern[k] == '$') {
31675 -                                               /* n is always > 0 */
31676 -                                               if (num < (size_t)n) {
31677 -                                                       buffer_append_string(p->location, list[num]);
31678 -                                               }
31679 -                                       } else {
31680 -                                               config_append_cond_match_buffer(con, p->conf.context, p->location, num);
31681 -                                       }
31682 -                                       
31683 -                                       k++;
31684 -                                       start = k + 1;
31685 -                               } 
31686 -                       }
31687 -                       
31688 -                       buffer_append_string_len(p->location, pattern + start, pattern_len - start);
31689 -                       
31690 -                       pcre_free(list);
31691 -                       
31692 -                       response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
31693 -                       
31694 -                       con->http_status = 301;
31695 -                       con->file_finished = 1;
31696 -                       
31697 -                       return HANDLER_FINISHED;
31698 -               }
31699 +       i = config_exec_pcre_keyvalue_buffer(con, p->conf.redirect, p->conf.context, p->match_buf, p->location);
31700 +
31701 +       if (i >= 0) {
31702 +               response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
31703 +
31704 +               con->http_status = 301;
31705 +               con->file_finished = 1;
31706 +
31707 +               return HANDLER_FINISHED;
31708 +       }
31709 +       else if (i != PCRE_ERROR_NOMATCH) {
31710 +               log_error_write(srv, __FILE__, __LINE__, "s",
31711 +                               "execution error while matching", i);
31712         }
31713  #undef N
31714 -               
31715 +
31716  #else
31717         UNUSED(srv);
31718         UNUSED(con);
31719         UNUSED(p_data);
31720  #endif
31721 -       
31722 +
31723         return HANDLER_GO_ON;
31724  }
31725  
31726 @@ -265,13 +207,13 @@
31727  int mod_redirect_plugin_init(plugin *p) {
31728         p->version     = LIGHTTPD_VERSION_ID;
31729         p->name        = buffer_init_string("redirect");
31730 -       
31731 +
31732         p->init        = mod_redirect_init;
31733         p->handle_uri_clean  = mod_redirect_uri_handler;
31734         p->set_defaults  = mod_redirect_set_defaults;
31735         p->cleanup     = mod_redirect_free;
31736 -       
31737 +
31738         p->data        = NULL;
31739 -       
31740 +
31741         return 0;
31742  }
31743 --- ../lighttpd-1.4.11/src/mod_rewrite.c        2005-09-29 20:59:10.000000000 +0300
31744 +++ lighttpd-1.4.12/src/mod_rewrite.c   2006-07-16 00:26:03.000000000 +0300
31745 @@ -13,24 +13,8 @@
31746  #endif
31747  
31748  typedef struct {
31749 -#ifdef HAVE_PCRE_H
31750 -       pcre *key;
31751 -#endif
31752 -       
31753 -       buffer *value;
31754 -       
31755 -       int once;
31756 -} rewrite_rule;
31757 -
31758 -typedef struct {
31759 -       rewrite_rule **ptr;
31760 -       
31761 -       size_t used;
31762 -       size_t size;
31763 -} rewrite_rule_buffer;
31764 -
31765 -typedef struct {
31766 -       rewrite_rule_buffer *rewrite;
31767 +       pcre_keyvalue_buffer *rewrite;
31768 +       buffer *once;
31769         data_config *context; /* to which apply me */
31770  } plugin_config;
31771  
31772 @@ -42,20 +26,20 @@
31773  typedef struct {
31774         PLUGIN_DATA;
31775         buffer *match_buf;
31776 -       
31777 +
31778         plugin_config **config_storage;
31779 -       
31780 -       plugin_config conf; 
31781 +
31782 +       plugin_config conf;
31783  } plugin_data;
31784  
31785  static handler_ctx * handler_ctx_init() {
31786         handler_ctx * hctx;
31787 -       
31788 +
31789         hctx = calloc(1, sizeof(*hctx));
31790 -       
31791 +
31792         hctx->state = REWRITE_STATE_UNSET;
31793         hctx->loops = 0;
31794 -       
31795 +
31796         return hctx;
31797  }
31798  
31799 @@ -63,207 +47,136 @@
31800         free(hctx);
31801  }
31802  
31803 -rewrite_rule_buffer *rewrite_rule_buffer_init(void) {
31804 -       rewrite_rule_buffer *kvb;
31805 -       
31806 -       kvb = calloc(1, sizeof(*kvb));
31807 -       
31808 -       return kvb;
31809 -}
31810 -
31811 -int rewrite_rule_buffer_append(rewrite_rule_buffer *kvb, buffer *key, buffer *value, int once) {
31812 -#ifdef HAVE_PCRE_H
31813 -       size_t i;
31814 -       const char *errptr;
31815 -       int erroff;
31816 -       
31817 -       if (!key) return -1;
31818 -
31819 -       if (kvb->size == 0) {
31820 -               kvb->size = 4;
31821 -               kvb->used = 0;
31822 -               
31823 -               kvb->ptr = malloc(kvb->size * sizeof(*kvb->ptr));
31824 -               
31825 -               for(i = 0; i < kvb->size; i++) {
31826 -                       kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
31827 -               }
31828 -       } else if (kvb->used == kvb->size) {
31829 -               kvb->size += 4;
31830 -               
31831 -               kvb->ptr = realloc(kvb->ptr, kvb->size * sizeof(*kvb->ptr));
31832 -               
31833 -               for(i = kvb->used; i < kvb->size; i++) {
31834 -                       kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
31835 -               }
31836 -       }
31837 -       
31838 -       if (NULL == (kvb->ptr[kvb->used]->key = pcre_compile(key->ptr,
31839 -                                                           0, &errptr, &erroff, NULL))) {
31840 -               
31841 -               return -1;
31842 -       }
31843 -       
31844 -       kvb->ptr[kvb->used]->value = buffer_init();
31845 -       buffer_copy_string_buffer(kvb->ptr[kvb->used]->value, value);
31846 -       kvb->ptr[kvb->used]->once = once;
31847 -       
31848 -       kvb->used++;
31849 -       
31850 -       return 0;
31851 -#else
31852 -       UNUSED(kvb);
31853 -       UNUSED(value);
31854 -       UNUSED(once);
31855 -       UNUSED(key);
31856 -
31857 -       return -1;
31858 -#endif
31859 -}
31860 -
31861 -void rewrite_rule_buffer_free(rewrite_rule_buffer *kvb) {
31862 -#ifdef HAVE_PCRE_H
31863 -       size_t i;
31864 -
31865 -       for (i = 0; i < kvb->size; i++) {
31866 -               if (kvb->ptr[i]->key) pcre_free(kvb->ptr[i]->key);
31867 -               if (kvb->ptr[i]->value) buffer_free(kvb->ptr[i]->value);
31868 -               free(kvb->ptr[i]);
31869 -       }
31870 -       
31871 -       if (kvb->ptr) free(kvb->ptr);
31872 -#endif
31873 -       
31874 -       free(kvb);
31875 -}
31876 -
31877  
31878  INIT_FUNC(mod_rewrite_init) {
31879         plugin_data *p;
31880 -       
31881 +
31882         p = calloc(1, sizeof(*p));
31883 -       
31884 +
31885         p->match_buf = buffer_init();
31886 -       
31887 +
31888         return p;
31889  }
31890  
31891  FREE_FUNC(mod_rewrite_free) {
31892         plugin_data *p = p_d;
31893 -       
31894 +
31895         UNUSED(srv);
31896  
31897         if (!p) return HANDLER_GO_ON;
31898 -       
31899 +
31900         buffer_free(p->match_buf);
31901         if (p->config_storage) {
31902                 size_t i;
31903                 for (i = 0; i < srv->config_context->used; i++) {
31904                         plugin_config *s = p->config_storage[i];
31905 -                       rewrite_rule_buffer_free(s->rewrite);
31906 -                       
31907 +                       pcre_keyvalue_buffer_free(s->rewrite);
31908 +                       buffer_free(s->once);
31909 +
31910                         free(s);
31911                 }
31912                 free(p->config_storage);
31913         }
31914 -       
31915 +
31916         free(p);
31917 -       
31918 +
31919         return HANDLER_GO_ON;
31920  }
31921  
31922  static int parse_config_entry(server *srv, plugin_config *s, array *ca, const char *option, int once) {
31923         data_unset *du;
31924 -       
31925 +
31926         if (NULL != (du = array_get_element(ca, option))) {
31927                 data_array *da = (data_array *)du;
31928                 size_t j;
31929 -               
31930 +
31931                 if (du->type != TYPE_ARRAY) {
31932 -                       log_error_write(srv, __FILE__, __LINE__, "sss", 
31933 +                       log_error_write(srv, __FILE__, __LINE__, "sss",
31934                                         "unexpected type for key: ", option, "array of strings");
31935 -                       
31936 +
31937                         return HANDLER_ERROR;
31938                 }
31939 -               
31940 +
31941                 da = (data_array *)du;
31942 -               
31943 +
31944                 for (j = 0; j < da->value->used; j++) {
31945                         if (da->value->data[j]->type != TYPE_STRING) {
31946 -                               log_error_write(srv, __FILE__, __LINE__, "sssbs", 
31947 -                                               "unexpected type for key: ", 
31948 -                                               option, 
31949 +                               log_error_write(srv, __FILE__, __LINE__, "sssbs",
31950 +                                               "unexpected type for key: ",
31951 +                                               option,
31952                                                 "[", da->value->data[j]->key, "](string)");
31953 -                               
31954 +
31955                                 return HANDLER_ERROR;
31956                         }
31957 -                       
31958 -                       if (0 != rewrite_rule_buffer_append(s->rewrite, 
31959 -                                                           ((data_string *)(da->value->data[j]))->key,
31960 -                                                           ((data_string *)(da->value->data[j]))->value,
31961 -                                                           once)) {
31962 +
31963 +                       if (0 != pcre_keyvalue_buffer_append(s->rewrite,
31964 +                                                           ((data_string *)(da->value->data[j]))->key->ptr,
31965 +                                                           ((data_string *)(da->value->data[j]))->value->ptr)) {
31966  #ifdef HAVE_PCRE_H
31967 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
31968 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
31969                                                 "pcre-compile failed for", da->value->data[j]->key);
31970  #else
31971 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
31972 +                               log_error_write(srv, __FILE__, __LINE__, "s",
31973                                                 "pcre support is missing, please install libpcre and the headers");
31974  #endif
31975                         }
31976 +
31977 +                       if (once) {
31978 +                               buffer_append_string_len(s->once, CONST_STR_LEN("1"));
31979 +                       } else {
31980 +                               buffer_append_string_len(s->once, CONST_STR_LEN("0"));
31981 +                       }
31982                 }
31983         }
31984 -       
31985 +
31986         return 0;
31987  }
31988  
31989  SETDEFAULTS_FUNC(mod_rewrite_set_defaults) {
31990         plugin_data *p = p_d;
31991         size_t i = 0;
31992 -       
31993 -       config_values_t cv[] = { 
31994 +
31995 +       config_values_t cv[] = {
31996                 { "url.rewrite-repeat",        NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
31997                 { "url.rewrite-once",          NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
31998 -               
31999 -               /* old names, still supported 
32000 -                * 
32001 +
32002 +               /* old names, still supported
32003 +                *
32004                  * url.rewrite remapped to url.rewrite-once
32005                  * url.rewrite-final    is url.rewrite-once
32006 -                * 
32007 +                *
32008                  */
32009                 { "url.rewrite",               NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
32010                 { "url.rewrite-final",         NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
32011                 { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
32012         };
32013 -       
32014 +
32015         if (!p) return HANDLER_ERROR;
32016 -       
32017 +
32018         /* 0 */
32019         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
32020 -       
32021 +
32022         for (i = 0; i < srv->config_context->used; i++) {
32023                 plugin_config *s;
32024                 array *ca;
32025 -               
32026 +
32027                 s = calloc(1, sizeof(plugin_config));
32028 -               s->rewrite   = rewrite_rule_buffer_init();
32029 -               
32030 -               cv[0].destination = s->rewrite;
32031 -               cv[1].destination = s->rewrite;
32032 -               cv[2].destination = s->rewrite;
32033 -               
32034 +               s->rewrite   = pcre_keyvalue_buffer_init();
32035 +               s->once      = buffer_init();
32036 +
32037                 p->config_storage[i] = s;
32038                 ca = ((data_config *)srv->config_context->data[i])->value;
32039 -       
32040 +
32041                 if (0 != config_insert_values_global(srv, ca, cv)) {
32042                         return HANDLER_ERROR;
32043                 }
32044 -               
32045 +
32046                 parse_config_entry(srv, s, ca, "url.rewrite-once",   1);
32047                 parse_config_entry(srv, s, ca, "url.rewrite-final",  1);
32048                 parse_config_entry(srv, s, ca, "url.rewrite",        1);
32049                 parse_config_entry(srv, s, ca, "url.rewrite-repeat", 0);
32050         }
32051 -       
32052 +
32053         return HANDLER_GO_ON;
32054  }
32055  #ifdef HAVE_PCRE_H
32056 @@ -271,157 +184,107 @@
32057         size_t i, j;
32058         plugin_config *s = p->config_storage[0];
32059         p->conf.rewrite = s->rewrite;
32060 -       
32061 +       p->conf.once    = s->once;
32062 +
32063         /* skip the first, the global context */
32064         for (i = 1; i < srv->config_context->used; i++) {
32065                 data_config *dc = (data_config *)srv->config_context->data[i];
32066                 s = p->config_storage[i];
32067 -               
32068 +
32069                 if (COMP_HTTP_URL == dc->comp) continue;
32070 -               
32071 +
32072                 /* condition didn't match */
32073                 if (!config_check_cond(srv, con, dc)) continue;
32074 -               
32075 +
32076                 /* merge config */
32077                 for (j = 0; j < dc->value->used; j++) {
32078                         data_unset *du = dc->value->data[j];
32079 -                       
32080 +
32081                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite"))) {
32082                                 p->conf.rewrite = s->rewrite;
32083 +                               p->conf.once    = s->once;
32084                                 p->conf.context = dc;
32085                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-once"))) {
32086                                 p->conf.rewrite = s->rewrite;
32087 +                               p->conf.once    = s->once;
32088                                 p->conf.context = dc;
32089                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-repeat"))) {
32090                                 p->conf.rewrite = s->rewrite;
32091 +                               p->conf.once    = s->once;
32092                                 p->conf.context = dc;
32093                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-final"))) {
32094                                 p->conf.rewrite = s->rewrite;
32095 +                               p->conf.once    = s->once;
32096                                 p->conf.context = dc;
32097                         }
32098                 }
32099         }
32100 -       
32101 +
32102         return 0;
32103  }
32104  #endif
32105  URIHANDLER_FUNC(mod_rewrite_con_reset) {
32106         plugin_data *p = p_d;
32107 -       
32108 +
32109         UNUSED(srv);
32110 -       
32111 +
32112         if (con->plugin_ctx[p->id]) {
32113                 handler_ctx_free(con->plugin_ctx[p->id]);
32114                 con->plugin_ctx[p->id] = NULL;
32115         }
32116 -       
32117 +
32118         return HANDLER_GO_ON;
32119  }
32120  
32121  URIHANDLER_FUNC(mod_rewrite_uri_handler) {
32122  #ifdef HAVE_PCRE_H
32123         plugin_data *p = p_d;
32124 -       size_t i;
32125 +       int i;
32126         handler_ctx *hctx;
32127  
32128 -       /* 
32129 +       /*
32130          * REWRITE URL
32131 -        * 
32132 +        *
32133          * e.g. rewrite /base/ to /index.php?section=base
32134 -        * 
32135 +        *
32136          */
32137 -       
32138 +
32139         if (con->plugin_ctx[p->id]) {
32140                 hctx = con->plugin_ctx[p->id];
32141 -               
32142 +
32143                 if (hctx->loops++ > 100) {
32144 -                       log_error_write(srv, __FILE__, __LINE__,  "s",  
32145 +                       log_error_write(srv, __FILE__, __LINE__,  "s",
32146                                         "ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request, perhaps you want to use url.rewrite-once instead of url.rewrite-repeat");
32147 -                       
32148 +
32149                         return HANDLER_ERROR;
32150                 }
32151 -               
32152 +
32153                 if (hctx->state == REWRITE_STATE_FINISHED) return HANDLER_GO_ON;
32154         }
32155 -       
32156 +
32157         mod_rewrite_patch_connection(srv, con, p);
32158  
32159         if (!p->conf.rewrite) return HANDLER_GO_ON;
32160 -       
32161 +
32162         buffer_copy_string_buffer(p->match_buf, con->request.uri);
32163 -       
32164 -       for (i = 0; i < p->conf.rewrite->used; i++) {
32165 -               pcre *match;
32166 -               const char *pattern;
32167 -               size_t pattern_len;
32168 -               int n;
32169 -               rewrite_rule *rule = p->conf.rewrite->ptr[i];
32170 -# define N 10
32171 -               int ovec[N * 3];
32172 -               
32173 -               match       = rule->key;
32174 -               pattern     = rule->value->ptr;
32175 -               pattern_len = rule->value->used - 1;
32176 -               
32177 -               if ((n = pcre_exec(match, NULL, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
32178 -                       if (n != PCRE_ERROR_NOMATCH) {
32179 -                               log_error_write(srv, __FILE__, __LINE__, "sd",
32180 -                                               "execution error while matching: ", n);
32181 -                               return HANDLER_ERROR;
32182 -                       }
32183 -               } else {
32184 -                       const char **list;
32185 -                       size_t start, end;
32186 -                       size_t k;
32187 -                       
32188 -                       /* it matched */
32189 -                       pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
32190 -                       
32191 -                       /* search for $[0-9] */
32192 -                       
32193 -                       buffer_reset(con->request.uri);
32194 -                       
32195 -                       start = 0; end = pattern_len;
32196 -                       for (k = 0; k < pattern_len; k++) {
32197 -                               if ((pattern[k] == '$' || pattern[k] == '%') &&
32198 -                                   isdigit((unsigned char)pattern[k + 1])) {
32199 -                                       /* got one */
32200 -                                       
32201 -                                       size_t num = pattern[k + 1] - '0';
32202 -                                       
32203 -                                       end = k;
32204 -                                       
32205 -                                       buffer_append_string_len(con->request.uri, pattern + start, end - start);
32206 -                                       
32207 -                                       if (pattern[k] == '$') {
32208 -                                               /* n is always > 0 */
32209 -                                               if (num < (size_t)n) {
32210 -                                                       buffer_append_string(con->request.uri, list[num]);
32211 -                                               }
32212 -                                       } else {
32213 -                                               config_append_cond_match_buffer(con, p->conf.context, con->request.uri, num);
32214 -                                       }
32215 -                                       
32216 -                                       k++;
32217 -                                       start = k + 1;
32218 -                               } 
32219 -                       }
32220 -                       
32221 -                       buffer_append_string_len(con->request.uri, pattern + start, pattern_len - start);
32222 -                       
32223 -                       pcre_free(list);
32224 -                       
32225 -                       hctx = handler_ctx_init();
32226 -                               
32227 -                       con->plugin_ctx[p->id] = hctx;
32228 -                       
32229 -                       if (rule->once) hctx->state = REWRITE_STATE_FINISHED;
32230 -                       
32231 -                       return HANDLER_COMEBACK;
32232 -               }
32233 +       i = config_exec_pcre_keyvalue_buffer(con, p->conf.rewrite, p->conf.context, p->match_buf, con->request.uri);
32234 +
32235 +       if (i >= 0) {
32236 +               hctx = handler_ctx_init();
32237 +
32238 +               con->plugin_ctx[p->id] = hctx;
32239 +
32240 +               if (p->conf.once->ptr[i] == '1')
32241 +                       hctx->state = REWRITE_STATE_FINISHED;
32242 +
32243 +               return HANDLER_COMEBACK;
32244 +       }
32245 +       else if (i != PCRE_ERROR_NOMATCH) {
32246 +               log_error_write(srv, __FILE__, __LINE__, "s",
32247 +                               "execution error while matching", i);
32248         }
32249  #undef N
32250 -               
32251 +
32252  #else
32253         UNUSED(srv);
32254         UNUSED(con);
32255 @@ -434,17 +297,17 @@
32256  int mod_rewrite_plugin_init(plugin *p) {
32257         p->version     = LIGHTTPD_VERSION_ID;
32258         p->name        = buffer_init_string("rewrite");
32259 -       
32260 +
32261         p->init        = mod_rewrite_init;
32262         /* it has to stay _raw as we are matching on uri + querystring
32263          */
32264 -       
32265 +
32266         p->handle_uri_raw = mod_rewrite_uri_handler;
32267         p->set_defaults = mod_rewrite_set_defaults;
32268         p->cleanup     = mod_rewrite_free;
32269         p->connection_reset = mod_rewrite_con_reset;
32270 -       
32271 +
32272         p->data        = NULL;
32273 -       
32274 +
32275         return 0;
32276  }
32277 --- ../lighttpd-1.4.11/src/mod_rrdtool.c        2005-08-22 01:52:24.000000000 +0300
32278 +++ lighttpd-1.4.12/src/mod_rrdtool.c   2006-07-18 13:03:40.000000000 +0300
32279 @@ -5,7 +5,6 @@
32280  #include <stdlib.h>
32281  #include <stdio.h>
32282  #include <string.h>
32283 -#include <unistd.h>
32284  #include <errno.h>
32285  #include <time.h>
32286  
32287 @@ -20,10 +19,14 @@
32288  /* no need for waitpid if we don't have fork */
32289  #include <sys/wait.h>
32290  #endif
32291 +
32292 +#include "sys-files.h"
32293 +#include "sys-process.h"
32294 +
32295  typedef struct {
32296         buffer *path_rrdtool_bin;
32297         buffer *path_rrd;
32298 -       
32299 +
32300         double requests, *requests_ptr;
32301         double bytes_written, *bytes_written_ptr;
32302         double bytes_read, *bytes_read_ptr;
32303 @@ -31,84 +34,84 @@
32304  
32305  typedef struct {
32306         PLUGIN_DATA;
32307 -       
32308 +
32309         buffer *cmd;
32310         buffer *resp;
32311 -       
32312 +
32313         int read_fd, write_fd;
32314         pid_t rrdtool_pid;
32315 -       
32316 +
32317         int rrdtool_running;
32318 -       
32319 +
32320         plugin_config **config_storage;
32321         plugin_config conf;
32322  } plugin_data;
32323  
32324  INIT_FUNC(mod_rrd_init) {
32325         plugin_data *p;
32326 -       
32327 +
32328         p = calloc(1, sizeof(*p));
32329 -       
32330 +
32331         p->resp = buffer_init();
32332         p->cmd = buffer_init();
32333 -       
32334 +
32335         return p;
32336  }
32337  
32338  FREE_FUNC(mod_rrd_free) {
32339         plugin_data *p = p_d;
32340         size_t i;
32341 -       
32342 +
32343         if (!p) return HANDLER_GO_ON;
32344 -       
32345 +
32346         if (p->config_storage) {
32347                 for (i = 0; i < srv->config_context->used; i++) {
32348                         plugin_config *s = p->config_storage[i];
32349 -                       
32350 +
32351                         buffer_free(s->path_rrdtool_bin);
32352                         buffer_free(s->path_rrd);
32353 -                       
32354 +
32355                         free(s);
32356                 }
32357         }
32358         buffer_free(p->cmd);
32359         buffer_free(p->resp);
32360 -       
32361 +
32362         free(p->config_storage);
32363 -       
32364 +
32365         if (p->rrdtool_pid) {
32366                 int status;
32367                 close(p->read_fd);
32368                 close(p->write_fd);
32369 -#ifdef HAVE_FORK       
32370 +#ifdef HAVE_FORK
32371                 /* collect status */
32372                 waitpid(p->rrdtool_pid, &status, 0);
32373  #endif
32374         }
32375 -       
32376 +
32377         free(p);
32378 -       
32379 +
32380         return HANDLER_GO_ON;
32381  }
32382  
32383  int mod_rrd_create_pipe(server *srv, plugin_data *p) {
32384         pid_t pid;
32385 -       
32386 +
32387         int to_rrdtool_fds[2];
32388         int from_rrdtool_fds[2];
32389 -#ifdef HAVE_FORK       
32390 +#ifdef HAVE_FORK
32391         if (pipe(to_rrdtool_fds)) {
32392 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
32393 +               log_error_write(srv, __FILE__, __LINE__, "ss",
32394                                 "pipe failed: ", strerror(errno));
32395                 return -1;
32396         }
32397 -       
32398 +
32399         if (pipe(from_rrdtool_fds)) {
32400 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
32401 +               log_error_write(srv, __FILE__, __LINE__, "ss",
32402                                 "pipe failed: ", strerror(errno));
32403                 return -1;
32404         }
32405 -       
32406 +
32407         /* fork, execve */
32408         switch (pid = fork()) {
32409         case 0: {
32410 @@ -117,33 +120,28 @@
32411                 int argc;
32412                 int i = 0;
32413                 char *dash = "-";
32414 -               
32415 +
32416                 /* move stdout to from_rrdtool_fd[1] */
32417                 close(STDOUT_FILENO);
32418                 dup2(from_rrdtool_fds[1], STDOUT_FILENO);
32419                 close(from_rrdtool_fds[1]);
32420                 /* not needed */
32421                 close(from_rrdtool_fds[0]);
32422 -               
32423 +
32424                 /* move the stdin to to_rrdtool_fd[0] */
32425                 close(STDIN_FILENO);
32426                 dup2(to_rrdtool_fds[0], STDIN_FILENO);
32427                 close(to_rrdtool_fds[0]);
32428                 /* not needed */
32429                 close(to_rrdtool_fds[1]);
32430 -               
32431 +
32432                 close(STDERR_FILENO);
32433 -               
32434 -               if (srv->errorlog_mode == ERRORLOG_FILE) {
32435 -                       dup2(srv->errorlog_fd, STDERR_FILENO);
32436 -                       close(srv->errorlog_fd);
32437 -               }
32438 -               
32439 +
32440                 /* set up args */
32441                 argc = 3;
32442                 args = malloc(sizeof(*args) * argc);
32443                 i = 0;
32444 -               
32445 +
32446                 args[i++] = p->conf.path_rrdtool_bin->ptr;
32447                 args[i++] = dash;
32448                 args[i++] = NULL;
32449 @@ -152,12 +150,12 @@
32450                 for (i = 3; i < 256; i++) {
32451                         close(i);
32452                 }
32453 -               
32454 +
32455                 /* exec the cgi */
32456                 execv(args[0], args);
32457 -               
32458 +
32459                 log_error_write(srv, __FILE__, __LINE__, "sss", "spawing rrdtool failed: ", strerror(errno), args[0]);
32460 -               
32461 +
32462                 /* */
32463                 SEGFAULT();
32464                 break;
32465 @@ -168,19 +166,19 @@
32466                 break;
32467         default: {
32468                 /* father */
32469 -               
32470 +
32471                 close(from_rrdtool_fds[1]);
32472                 close(to_rrdtool_fds[0]);
32473 -               
32474 +
32475                 /* register PID and wait for them asyncronously */
32476                 p->write_fd = to_rrdtool_fds[1];
32477                 p->read_fd = from_rrdtool_fds[0];
32478                 p->rrdtool_pid = pid;
32479 -               
32480 +
32481                 break;
32482         }
32483         }
32484 -       
32485 +
32486         return 0;
32487  #else
32488         return -1;
32489 @@ -189,19 +187,19 @@
32490  
32491  static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) {
32492         struct stat st;
32493 -       
32494 +
32495         /* check if DB already exists */
32496         if (0 == stat(s->path_rrd->ptr, &st)) {
32497                 /* check if it is plain file */
32498                 if (!S_ISREG(st.st_mode)) {
32499 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
32500 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
32501                                         "not a regular file:", s->path_rrd);
32502                         return HANDLER_ERROR;
32503                 }
32504         } else {
32505                 int r ;
32506                 /* create a new one */
32507 -               
32508 +
32509                 BUFFER_COPY_STRING_CONST(p->cmd, "create ");
32510                 buffer_append_string_buffer(p->cmd, s->path_rrd);
32511                 buffer_append_string(p->cmd, " --step 60 ");
32512 @@ -220,158 +218,155 @@
32513                 buffer_append_string(p->cmd, "RRA:MIN:0.5:6:700 ");
32514                 buffer_append_string(p->cmd, "RRA:MIN:0.5:24:775 ");
32515                 buffer_append_string(p->cmd, "RRA:MIN:0.5:288:797\n");
32516 -               
32517 +
32518                 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
32519 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
32520 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
32521                                 "rrdtool-write: failed", strerror(errno));
32522 -                       
32523 +
32524                         return HANDLER_ERROR;
32525                 }
32526 -               
32527 +
32528                 buffer_prepare_copy(p->resp, 4096);
32529                 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
32530 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
32531 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
32532                                 "rrdtool-read: failed", strerror(errno));
32533 -                       
32534 +
32535                         return HANDLER_ERROR;
32536                 }
32537 -               
32538 +
32539                 p->resp->used = r;
32540 -               
32541 +
32542                 if (p->resp->ptr[0] != 'O' ||
32543                     p->resp->ptr[1] != 'K') {
32544 -                       log_error_write(srv, __FILE__, __LINE__, "sbb", 
32545 +                       log_error_write(srv, __FILE__, __LINE__, "sbb",
32546                                 "rrdtool-response:", p->cmd, p->resp);
32547 -                       
32548 +
32549                         return HANDLER_ERROR;
32550                 }
32551         }
32552 -       
32553 +
32554         return HANDLER_GO_ON;
32555  }
32556  
32557 -#define PATCH(x) \
32558 -       p->conf.x = s->x;
32559  static int mod_rrd_patch_connection(server *srv, connection *con, plugin_data *p) {
32560         size_t i, j;
32561         plugin_config *s = p->config_storage[0];
32562 -       
32563 -       PATCH(path_rrdtool_bin);
32564 -       PATCH(path_rrd);
32565 -       
32566 +
32567 +       PATCH_OPTION(path_rrdtool_bin);
32568 +       PATCH_OPTION(path_rrd);
32569 +
32570         p->conf.bytes_written_ptr = &(s->bytes_written);
32571         p->conf.bytes_read_ptr = &(s->bytes_read);
32572         p->conf.requests_ptr = &(s->requests);
32573 -       
32574 +
32575         /* skip the first, the global context */
32576         for (i = 1; i < srv->config_context->used; i++) {
32577                 data_config *dc = (data_config *)srv->config_context->data[i];
32578                 s = p->config_storage[i];
32579 -               
32580 +
32581                 /* condition didn't match */
32582                 if (!config_check_cond(srv, con, dc)) continue;
32583 -               
32584 +
32585                 /* merge config */
32586                 for (j = 0; j < dc->value->used; j++) {
32587                         data_unset *du = dc->value->data[j];
32588 -                       
32589 +
32590                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("rrdtool.db-name"))) {
32591 -                               PATCH(path_rrd);
32592 +                               PATCH_OPTION(path_rrd);
32593                                 /* get pointers to double values */
32594 -                               
32595 +
32596                                 p->conf.bytes_written_ptr = &(s->bytes_written);
32597                                 p->conf.bytes_read_ptr = &(s->bytes_read);
32598                                 p->conf.requests_ptr = &(s->requests);
32599                         }
32600                 }
32601         }
32602 -       
32603 +
32604         return 0;
32605  }
32606 -#undef PATCH
32607  
32608  SETDEFAULTS_FUNC(mod_rrd_set_defaults) {
32609         plugin_data *p = p_d;
32610         size_t i;
32611 -       
32612 -       config_values_t cv[] = { 
32613 +
32614 +       config_values_t cv[] = {
32615                 { "rrdtool.binary",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
32616                 { "rrdtool.db-name",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
32617                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
32618         };
32619 -       
32620 +
32621         if (!p) return HANDLER_ERROR;
32622 -       
32623 +
32624         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
32625 -       
32626 +
32627         for (i = 0; i < srv->config_context->used; i++) {
32628                 plugin_config *s;
32629 -               
32630 +
32631                 s = calloc(1, sizeof(plugin_config));
32632                 s->path_rrdtool_bin = buffer_init();
32633                 s->path_rrd = buffer_init();
32634                 s->requests = 0;
32635                 s->bytes_written = 0;
32636                 s->bytes_read = 0;
32637 -               
32638 +
32639                 cv[0].destination = s->path_rrdtool_bin;
32640                 cv[1].destination = s->path_rrd;
32641 -               
32642 +
32643                 p->config_storage[i] = s;
32644 -       
32645 +
32646                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
32647                         return HANDLER_ERROR;
32648                 }
32649 -               
32650 +
32651                 if (i > 0 && !buffer_is_empty(s->path_rrdtool_bin)) {
32652                         /* path_rrdtool_bin is a global option */
32653 -                       
32654 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
32655 +
32656 +                       log_error_write(srv, __FILE__, __LINE__, "s",
32657                                         "rrdtool.binary can only be set as a global option.");
32658 -                       
32659 +
32660                         return HANDLER_ERROR;
32661                 }
32662 -               
32663 +
32664         }
32665 -       
32666 +
32667         p->conf.path_rrdtool_bin = p->config_storage[0]->path_rrdtool_bin;
32668         p->rrdtool_running = 0;
32669 -       
32670 +
32671         /* check for dir */
32672 -       
32673 +
32674         if (buffer_is_empty(p->conf.path_rrdtool_bin)) {
32675 -               log_error_write(srv, __FILE__, __LINE__, "s", 
32676 +               log_error_write(srv, __FILE__, __LINE__, "s",
32677                                 "rrdtool.binary has to be set");
32678                 return HANDLER_ERROR;
32679         }
32680 -       
32681 +
32682         /* open the pipe to rrdtool */
32683         if (mod_rrd_create_pipe(srv, p)) {
32684                 return HANDLER_ERROR;
32685         }
32686 -       
32687 +
32688         p->rrdtool_running = 1;
32689 -               
32690 +
32691         return HANDLER_GO_ON;
32692  }
32693  
32694  TRIGGER_FUNC(mod_rrd_trigger) {
32695         plugin_data *p = p_d;
32696         size_t i;
32697 -       
32698 +
32699         if (!p->rrdtool_running) return HANDLER_GO_ON;
32700         if ((srv->cur_ts % 60) != 0) return HANDLER_GO_ON;
32701 -       
32702 +
32703         for (i = 0; i < srv->config_context->used; i++) {
32704                 plugin_config *s = p->config_storage[i];
32705                 int r;
32706 -               
32707 +
32708                 if (buffer_is_empty(s->path_rrd)) continue;
32709 -       
32710 +
32711                 /* write the data down every minute */
32712 -               
32713 +
32714                 if (HANDLER_GO_ON != mod_rrdtool_create_rrd(srv, p, s)) return HANDLER_ERROR;
32715 -               
32716 +
32717                 BUFFER_COPY_STRING_CONST(p->cmd, "update ");
32718                 buffer_append_string_buffer(p->cmd, s->path_rrd);
32719                 BUFFER_APPEND_STRING_CONST(p->cmd, " N:");
32720 @@ -381,69 +376,69 @@
32721                 BUFFER_APPEND_STRING_CONST(p->cmd, ":");
32722                 buffer_append_long(p->cmd, s->requests);
32723                 BUFFER_APPEND_STRING_CONST(p->cmd, "\n");
32724 -               
32725 +
32726                 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
32727                         p->rrdtool_running = 0;
32728 -                       
32729 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
32730 +
32731 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
32732                                         "rrdtool-write: failed", strerror(errno));
32733 -                       
32734 +
32735                         return HANDLER_ERROR;
32736                 }
32737 -               
32738 +
32739                 buffer_prepare_copy(p->resp, 4096);
32740                 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
32741                         p->rrdtool_running = 0;
32742 -                       
32743 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
32744 +
32745 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
32746                                         "rrdtool-read: failed", strerror(errno));
32747 -                       
32748 +
32749                         return HANDLER_ERROR;
32750                 }
32751 -               
32752 +
32753                 p->resp->used = r;
32754 -               
32755 +
32756                 if (p->resp->ptr[0] != 'O' ||
32757                     p->resp->ptr[1] != 'K') {
32758                         p->rrdtool_running = 0;
32759 -                       
32760 -                       log_error_write(srv, __FILE__, __LINE__, "sbb", 
32761 +
32762 +                       log_error_write(srv, __FILE__, __LINE__, "sbb",
32763                                         "rrdtool-response:", p->cmd, p->resp);
32764 -                       
32765 +
32766                         return HANDLER_ERROR;
32767                 }
32768                 s->requests = 0;
32769                 s->bytes_written = 0;
32770                 s->bytes_read = 0;
32771         }
32772 -       
32773 +
32774         return HANDLER_GO_ON;
32775  }
32776  
32777  REQUESTDONE_FUNC(mod_rrd_account) {
32778         plugin_data *p = p_d;
32779 -       
32780 +
32781         mod_rrd_patch_connection(srv, con, p);
32782 -       
32783 +
32784         *(p->conf.requests_ptr)      += 1;
32785         *(p->conf.bytes_written_ptr) += con->bytes_written;
32786         *(p->conf.bytes_read_ptr)    += con->bytes_read;
32787 -       
32788 +
32789         return HANDLER_GO_ON;
32790  }
32791  
32792  int mod_rrdtool_plugin_init(plugin *p) {
32793         p->version     = LIGHTTPD_VERSION_ID;
32794         p->name        = buffer_init_string("rrd");
32795 -       
32796 +
32797         p->init        = mod_rrd_init;
32798         p->cleanup     = mod_rrd_free;
32799         p->set_defaults= mod_rrd_set_defaults;
32800 -       
32801 +
32802         p->handle_trigger      = mod_rrd_trigger;
32803         p->handle_request_done = mod_rrd_account;
32804 -       
32805 +
32806         p->data        = NULL;
32807 -       
32808 +
32809         return 0;
32810  }
32811 --- ../lighttpd-1.4.11/src/mod_scgi.c   2006-03-04 17:15:26.000000000 +0200
32812 +++ lighttpd-1.4.12/src/mod_scgi.c      2006-07-18 13:03:40.000000000 +0300
32813 @@ -1,5 +1,4 @@
32814  #include <sys/types.h>
32815 -#include <unistd.h>
32816  #include <errno.h>
32817  #include <fcntl.h>
32818  #include <string.h>
32819 @@ -18,6 +17,7 @@
32820  #include "connections.h"
32821  #include "response.h"
32822  #include "joblist.h"
32823 +#include "http_resp.h"
32824  
32825  #include "plugin.h"
32826  
32827 @@ -30,7 +30,9 @@
32828  #endif
32829  
32830  #include "sys-socket.h"
32831 -
32832 +#include "sys-files.h"
32833 +#include "sys-strings.h"
32834 +#include "sys-process.h"
32835  
32836  #ifndef UNIX_PATH_MAX
32837  # define UNIX_PATH_MAX 108
32838 @@ -46,30 +48,29 @@
32839  enum {EOL_UNSET, EOL_N, EOL_RN};
32840  
32841  /*
32842 - * 
32843 + *
32844   * TODO:
32845 - * 
32846 + *
32847   * - add timeout for a connect to a non-scgi process
32848   *   (use state_timestamp + state)
32849 - * 
32850 + *
32851   */
32852  
32853  typedef struct scgi_proc {
32854         size_t id; /* id will be between 1 and max_procs */
32855         buffer *socket; /* config.socket + "-" + id */
32856         unsigned port;  /* config.port + pno */
32857 -       
32858 -       pid_t pid;   /* PID of the spawned process (0 if not spawned locally) */
32859  
32860 +       pid_t pid;   /* PID of the spawned process (0 if not spawned locally) */
32861  
32862         size_t load; /* number of requests waiting on this process */
32863  
32864         time_t last_used; /* see idle_timeout */
32865         size_t requests;  /* see max_requests */
32866         struct scgi_proc *prev, *next; /* see first */
32867 -       
32868 +
32869         time_t disable_ts; /* replace by host->something */
32870 -       
32871 +
32872         int is_local;
32873  
32874         enum { PROC_STATE_UNSET,            /* init-phase */
32875 @@ -78,7 +79,7 @@
32876                         PROC_STATE_KILLED,  /* was killed as we don't have the load anymore */
32877                         PROC_STATE_DIED,    /* marked as dead, should be restarted */
32878                         PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
32879 -       } state; 
32880 +       } state;
32881  } scgi_proc;
32882  
32883  typedef struct {
32884 @@ -86,20 +87,20 @@
32885          * sorted by lowest load
32886          *
32887          * whenever a job is done move it up in the list
32888 -        * until it is sorted, move it down as soon as the 
32889 +        * until it is sorted, move it down as soon as the
32890          * job is started
32891          */
32892 -       scgi_proc *first; 
32893 -       scgi_proc *unused_procs; 
32894 +       scgi_proc *first;
32895 +       scgi_proc *unused_procs;
32896  
32897 -       /* 
32898 +       /*
32899          * spawn at least min_procs, at max_procs.
32900          *
32901 -        * as soon as the load of the first entry 
32902 +        * as soon as the load of the first entry
32903          * is max_load_per_proc we spawn a new one
32904 -        * and add it to the first entry and give it 
32905 +        * and add it to the first entry and give it
32906          * the load
32907 -        * 
32908 +        *
32909          */
32910  
32911         unsigned short min_procs;
32912 @@ -111,44 +112,44 @@
32913  
32914         /*
32915          * kick the process from the list if it was not
32916 -        * used for idle_timeout until min_procs is 
32917 +        * used for idle_timeout until min_procs is
32918          * reached. this helps to get the processlist
32919          * small again we had a small peak load.
32920          *
32921          */
32922 -       
32923 +
32924         unsigned short idle_timeout;
32925 -       
32926 +
32927         /*
32928          * time after a disabled remote connection is tried to be re-enabled
32929 -        * 
32930 -        * 
32931 +        *
32932 +        *
32933          */
32934 -       
32935 +
32936         unsigned short disable_time;
32937  
32938         /*
32939          * same scgi processes get a little bit larger
32940 -        * than wanted. max_requests_per_proc kills a 
32941 +        * than wanted. max_requests_per_proc kills a
32942          * process after a number of handled requests.
32943          *
32944          */
32945         size_t max_requests_per_proc;
32946 -       
32947 +
32948  
32949         /* config */
32950  
32951 -       /* 
32952 -        * host:port 
32953 +       /*
32954 +        * host:port
32955          *
32956 -        * if host is one of the local IP adresses the 
32957 +        * if host is one of the local IP adresses the
32958          * whole connection is local
32959          *
32960          * if tcp/ip should be used host AND port have
32961 -        * to be specified 
32962 -        * 
32963 -        */ 
32964 -       buffer *host; 
32965 +        * to be specified
32966 +        *
32967 +        */
32968 +       buffer *host;
32969         unsigned short port;
32970  
32971         /*
32972 @@ -161,7 +162,7 @@
32973          */
32974         buffer *unixsocket;
32975  
32976 -       /* if socket is local we can start the scgi 
32977 +       /* if socket is local we can start the scgi
32978          * process ourself
32979          *
32980          * bin-path is the path to the binary
32981 @@ -169,19 +170,19 @@
32982          * check min_procs and max_procs for the number
32983          * of process to start-up
32984          */
32985 -       buffer *bin_path; 
32986 -       
32987 -       /* bin-path is set bin-environment is taken to 
32988 +       buffer *bin_path;
32989 +
32990 +       /* bin-path is set bin-environment is taken to
32991          * create the environement before starting the
32992          * FastCGI process
32993 -        * 
32994 +        *
32995          */
32996         array *bin_env;
32997 -       
32998 +
32999         array *bin_env_copy;
33000 -       
33001 +
33002         /*
33003 -        * docroot-translation between URL->phys and the 
33004 +        * docroot-translation between URL->phys and the
33005          * remote host
33006          *
33007          * reasons:
33008 @@ -192,7 +193,7 @@
33009         buffer *docroot;
33010  
33011         /*
33012 -        * check_local tell you if the phys file is stat()ed 
33013 +        * check_local tell you if the phys file is stat()ed
33014          * or not. FastCGI doesn't care if the service is
33015          * remote. If the web-server side doesn't contain
33016          * the scgi-files we should not stat() for them
33017 @@ -202,33 +203,33 @@
33018  
33019         /*
33020          * append PATH_INFO to SCRIPT_FILENAME
33021 -        * 
33022 +        *
33023          * php needs this if cgi.fix_pathinfo is provied
33024 -        * 
33025 +        *
33026          */
33027 -       
33028 +
33029         ssize_t load; /* replace by host->load */
33030  
33031         size_t max_id; /* corresponds most of the time to
33032         num_procs.
33033 -       
33034 +
33035         only if a process is killed max_id waits for the process itself
33036         to die and decrements its afterwards */
33037  } scgi_extension_host;
33038  
33039  /*
33040   * one extension can have multiple hosts assigned
33041 - * one host can spawn additional processes on the same 
33042 + * one host can spawn additional processes on the same
33043   *   socket (if we control it)
33044   *
33045   * ext -> host -> procs
33046   *    1:n     1:n
33047   *
33048 - * if the scgi process is remote that whole goes down 
33049 + * if the scgi process is remote that whole goes down
33050   * to
33051   *
33052   * ext -> host -> procs
33053 - *    1:n     1:1 
33054 + *    1:n     1:1
33055   *
33056   * in case of PHP and FCGI_CHILDREN we have again a procs
33057   * but we don't control it directly.
33058 @@ -239,7 +240,7 @@
33059         buffer *key; /* like .php */
33060  
33061         scgi_extension_host **hosts;
33062 -       
33063 +
33064         size_t used;
33065         size_t size;
33066  } scgi_extension;
33067 @@ -253,14 +254,14 @@
33068  
33069  
33070  typedef struct {
33071 -       scgi_exts *exts; 
33072 -       
33073 +       scgi_exts *exts;
33074 +
33075         int debug;
33076  } plugin_config;
33077  
33078  typedef struct {
33079         char **ptr;
33080 -       
33081 +
33082         size_t size;
33083         size_t used;
33084  } char_array;
33085 @@ -268,52 +269,51 @@
33086  /* generic plugin data, shared between all connections */
33087  typedef struct {
33088         PLUGIN_DATA;
33089 -       
33090 +
33091         buffer *scgi_env;
33092 -       
33093 +
33094         buffer *path;
33095 -       buffer *parse_response;
33096 -       
33097 +
33098 +       http_resp *resp;
33099 +
33100         plugin_config **config_storage;
33101 -       
33102 +
33103         plugin_config conf; /* this is only used as long as no handler_ctx is setup */
33104  } plugin_data;
33105  
33106  /* connection specific data */
33107 -typedef enum { FCGI_STATE_INIT, FCGI_STATE_CONNECT, FCGI_STATE_PREPARE_WRITE, 
33108 -               FCGI_STATE_WRITE, FCGI_STATE_READ 
33109 +typedef enum {
33110 +       SCGI_STATE_INIT,
33111 +       SCGI_STATE_CONNECT,
33112 +       SCGI_STATE_PREPARE_WRITE,
33113 +       SCGI_STATE_WRITE,
33114 +       SCGI_STATE_RESPONSE_HEADER,
33115 +       SCGI_STATE_RESPONSE_CONTENT,
33116 +       SCGI_STATE_ERROR
33117  } scgi_connection_state_t;
33118  
33119  typedef struct {
33120 -       buffer  *response; 
33121 -       size_t   response_len;
33122 -       int      response_type;
33123 -       int      response_padding;
33124 -       
33125         scgi_proc *proc;
33126         scgi_extension_host *host;
33127 -       
33128 +
33129         scgi_connection_state_t state;
33130         time_t   state_timestamp;
33131 -       
33132 +
33133         int      reconnects; /* number of reconnect attempts */
33134 -       
33135 -       read_buffer *rb;
33136 +
33137 +       chunkqueue *rb;
33138         chunkqueue *wb;
33139 -       
33140 -       buffer   *response_header;
33141 -       
33142 +
33143         int       delayed;   /* flag to mark that the connect() is delayed */
33144 -       
33145 +
33146         size_t    request_id;
33147 -       int       fd;        /* fd to the scgi process */
33148 -       int       fde_ndx;   /* index into the fd-event buffer */
33149 +       iosocket  *sock;        /* fd to the scgi process */
33150  
33151         pid_t     pid;
33152         int       got_proc;
33153 -       
33154 +
33155         plugin_config conf;
33156 -       
33157 +
33158         connection *remote_conn;  /* dumb pointer */
33159         plugin_data *plugin_data; /* dumb pointer */
33160  } handler_ctx;
33161 @@ -328,42 +328,30 @@
33162  
33163  static handler_ctx * handler_ctx_init() {
33164         handler_ctx * hctx;
33165 -       
33166 +
33167         hctx = calloc(1, sizeof(*hctx));
33168         assert(hctx);
33169 -       
33170 -       hctx->fde_ndx = -1;
33171 -       
33172 -       hctx->response = buffer_init();
33173 -       hctx->response_header = buffer_init();
33174 -       
33175 +
33176 +       hctx->sock = iosocket_init();;
33177 +
33178         hctx->request_id = 0;
33179 -       hctx->state = FCGI_STATE_INIT;
33180 +       hctx->state = SCGI_STATE_INIT;
33181         hctx->proc = NULL;
33182 -       
33183 -       hctx->response_len = 0;
33184 -       hctx->response_type = 0;
33185 -       hctx->response_padding = 0;
33186 -       hctx->fd = -1;
33187 -       
33188 +
33189         hctx->reconnects = 0;
33190  
33191         hctx->wb = chunkqueue_init();
33192 -       
33193 +       hctx->rb = chunkqueue_init();
33194 +
33195         return hctx;
33196  }
33197  
33198  static void handler_ctx_free(handler_ctx *hctx) {
33199 -       buffer_free(hctx->response);
33200 -       buffer_free(hctx->response_header);
33201 -
33202         chunkqueue_free(hctx->wb);
33203 -       
33204 -       if (hctx->rb) {
33205 -               if (hctx->rb->ptr) free(hctx->rb->ptr);
33206 -               free(hctx->rb);
33207 -       }
33208 -       
33209 +       chunkqueue_free(hctx->rb);
33210 +
33211 +       iosocket_free(hctx->sock);
33212 +
33213         free(hctx);
33214  }
33215  
33216 @@ -372,20 +360,20 @@
33217  
33218         f = calloc(1, sizeof(*f));
33219         f->socket = buffer_init();
33220 -       
33221 +
33222         f->prev = NULL;
33223         f->next = NULL;
33224 -       
33225 +
33226         return f;
33227  }
33228  
33229  void scgi_process_free(scgi_proc *f) {
33230         if (!f) return;
33231 -       
33232 +
33233         scgi_process_free(f->next);
33234 -       
33235 +
33236         buffer_free(f->socket);
33237 -       
33238 +
33239         free(f);
33240  }
33241  
33242 @@ -400,62 +388,62 @@
33243         f->bin_path = buffer_init();
33244         f->bin_env = array_init();
33245         f->bin_env_copy = array_init();
33246 -       
33247 +
33248         return f;
33249  }
33250  
33251  void scgi_host_free(scgi_extension_host *h) {
33252         if (!h) return;
33253 -       
33254 +
33255         buffer_free(h->host);
33256         buffer_free(h->unixsocket);
33257         buffer_free(h->docroot);
33258         buffer_free(h->bin_path);
33259         array_free(h->bin_env);
33260         array_free(h->bin_env_copy);
33261 -       
33262 +
33263         scgi_process_free(h->first);
33264         scgi_process_free(h->unused_procs);
33265 -       
33266 +
33267         free(h);
33268 -       
33269 +
33270  }
33271  
33272  scgi_exts *scgi_extensions_init() {
33273         scgi_exts *f;
33274  
33275         f = calloc(1, sizeof(*f));
33276 -       
33277 +
33278         return f;
33279  }
33280  
33281  void scgi_extensions_free(scgi_exts *f) {
33282         size_t i;
33283 -       
33284 +
33285         if (!f) return;
33286 -       
33287 +
33288         for (i = 0; i < f->used; i++) {
33289                 scgi_extension *fe;
33290                 size_t j;
33291 -               
33292 +
33293                 fe = f->exts[i];
33294 -               
33295 +
33296                 for (j = 0; j < fe->used; j++) {
33297                         scgi_extension_host *h;
33298 -                       
33299 +
33300                         h = fe->hosts[j];
33301 -                       
33302 +
33303                         scgi_host_free(h);
33304                 }
33305 -               
33306 +
33307                 buffer_free(fe->key);
33308                 free(fe->hosts);
33309 -               
33310 +
33311                 free(fe);
33312         }
33313 -       
33314 +
33315         free(f->exts);
33316 -       
33317 +
33318         free(f);
33319  }
33320  
33321 @@ -504,99 +492,103 @@
33322                 assert(fe->hosts);
33323         }
33324  
33325 -       fe->hosts[fe->used++] = fh; 
33326 +       fe->hosts[fe->used++] = fh;
33327  
33328         return 0;
33329 -       
33330 +
33331  }
33332  
33333  INIT_FUNC(mod_scgi_init) {
33334         plugin_data *p;
33335 -       
33336 +
33337         p = calloc(1, sizeof(*p));
33338 -       
33339 +
33340         p->scgi_env = buffer_init();
33341 -       
33342 +
33343         p->path = buffer_init();
33344 -       p->parse_response = buffer_init();
33345 -       
33346 +       p->resp = http_response_init();
33347 +
33348         return p;
33349  }
33350  
33351  
33352  FREE_FUNC(mod_scgi_free) {
33353         plugin_data *p = p_d;
33354 -       
33355 +
33356         UNUSED(srv);
33357  
33358         buffer_free(p->scgi_env);
33359         buffer_free(p->path);
33360 -       buffer_free(p->parse_response);
33361 -       
33362 +       http_response_free(p->resp);
33363 +
33364         if (p->config_storage) {
33365                 size_t i, j, n;
33366                 for (i = 0; i < srv->config_context->used; i++) {
33367                         plugin_config *s = p->config_storage[i];
33368                         scgi_exts *exts;
33369 -                       
33370 +
33371                         if (!s) continue;
33372 -                       
33373 +
33374                         exts = s->exts;
33375  
33376                         for (j = 0; j < exts->used; j++) {
33377                                 scgi_extension *ex;
33378 -                               
33379 +
33380                                 ex = exts->exts[j];
33381 -                               
33382 +
33383                                 for (n = 0; n < ex->used; n++) {
33384                                         scgi_proc *proc;
33385                                         scgi_extension_host *host;
33386 -                                       
33387 +
33388                                         host = ex->hosts[n];
33389 -                                       
33390 +
33391                                         for (proc = host->first; proc; proc = proc->next) {
33392 +#ifndef _WIN32
33393                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
33394 -                                               
33395 -                                               if (proc->is_local && 
33396 +#endif
33397 +
33398 +                                               if (proc->is_local &&
33399                                                     !buffer_is_empty(proc->socket)) {
33400                                                         unlink(proc->socket->ptr);
33401                                                 }
33402                                         }
33403 -                                       
33404 +
33405                                         for (proc = host->unused_procs; proc; proc = proc->next) {
33406 +#ifndef _WIN32
33407                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
33408 -                                               
33409 -                                               if (proc->is_local && 
33410 +#endif
33411 +
33412 +                                               if (proc->is_local &&
33413                                                     !buffer_is_empty(proc->socket)) {
33414                                                         unlink(proc->socket->ptr);
33415                                                 }
33416                                         }
33417                                 }
33418                         }
33419 -                       
33420 +
33421                         scgi_extensions_free(s->exts);
33422 -                       
33423 +
33424                         free(s);
33425                 }
33426                 free(p->config_storage);
33427         }
33428 -       
33429 +
33430         free(p);
33431 -       
33432 +
33433         return HANDLER_GO_ON;
33434  }
33435  
33436  static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
33437         char *dst;
33438 -       
33439 +
33440         if (!key || !val) return -1;
33441 -       
33442 +
33443         dst = malloc(key_len + val_len + 3);
33444         memcpy(dst, key, key_len);
33445         dst[key_len] = '=';
33446         /* add the \0 from the value */
33447         memcpy(dst + key_len + 1, val, val_len + 1);
33448 -       
33449 +
33450         if (env->size == 0) {
33451                 env->size = 16;
33452                 env->ptr = malloc(env->size * sizeof(*env->ptr));
33453 @@ -604,13 +596,13 @@
33454                 env->size += 16;
33455                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
33456         }
33457 -       
33458 +
33459         env->ptr[env->used++] = dst;
33460 -       
33461 +
33462         return 0;
33463  }
33464  
33465 -static int scgi_spawn_connection(server *srv, 
33466 +static int scgi_spawn_connection(server *srv,
33467                                  plugin_data *p,
33468                                  scgi_extension_host *host,
33469                                  scgi_proc *proc) {
33470 @@ -622,31 +614,27 @@
33471  #endif
33472         struct sockaddr_in scgi_addr_in;
33473         struct sockaddr *scgi_addr;
33474 -       
33475 +
33476         socklen_t servlen;
33477 -       
33478 +
33479  #ifndef HAVE_FORK
33480         return -1;
33481  #endif
33482 -       
33483 +
33484         if (p->conf.debug) {
33485                 log_error_write(srv, __FILE__, __LINE__, "sdb",
33486                                 "new proc, socket:", proc->port, proc->socket);
33487         }
33488 -               
33489 +
33490         if (!buffer_is_empty(proc->socket)) {
33491                 memset(&scgi_addr, 0, sizeof(scgi_addr));
33492 -               
33493 +
33494  #ifdef HAVE_SYS_UN_H
33495                 scgi_addr_un.sun_family = AF_UNIX;
33496                 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
33497 -               
33498 -#ifdef SUN_LEN
33499 +
33500                 servlen = SUN_LEN(&scgi_addr_un);
33501 -#else
33502 -               /* stevens says: */
33503 -               servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
33504 -#endif
33505 +
33506                 socket_type = AF_UNIX;
33507                 scgi_addr = (struct sockaddr *) &scgi_addr_un;
33508  #else
33509 @@ -656,115 +644,115 @@
33510  #endif
33511         } else {
33512                 scgi_addr_in.sin_family = AF_INET;
33513 -               
33514 +
33515                 if (buffer_is_empty(host->host)) {
33516                         scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
33517                 } else {
33518                         struct hostent *he;
33519 -                       
33520 +
33521                         /* set a usefull default */
33522                         scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
33523 -                       
33524 -                       
33525 +
33526 +
33527                         if (NULL == (he = gethostbyname(host->host->ptr))) {
33528 -                               log_error_write(srv, __FILE__, __LINE__, 
33529 -                                               "sdb", "gethostbyname failed: ", 
33530 +                               log_error_write(srv, __FILE__, __LINE__,
33531 +                                               "sdb", "gethostbyname failed: ",
33532                                                 h_errno, host->host);
33533                                 return -1;
33534                         }
33535 -                       
33536 +
33537                         if (he->h_addrtype != AF_INET) {
33538                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
33539                                 return -1;
33540                         }
33541 -                       
33542 +
33543                         if (he->h_length != sizeof(struct in_addr)) {
33544                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
33545                                 return -1;
33546                         }
33547 -                       
33548 +
33549                         memcpy(&(scgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
33550 -                       
33551 +
33552                 }
33553                 scgi_addr_in.sin_port = htons(proc->port);
33554                 servlen = sizeof(scgi_addr_in);
33555 -               
33556 +
33557                 socket_type = AF_INET;
33558                 scgi_addr = (struct sockaddr *) &scgi_addr_in;
33559         }
33560 -       
33561 +
33562         if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
33563 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
33564 +               log_error_write(srv, __FILE__, __LINE__, "ss",
33565                                 "failed:", strerror(errno));
33566                 return -1;
33567         }
33568 -       
33569 +
33570         if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
33571                 /* server is not up, spawn in  */
33572                 pid_t child;
33573                 int val;
33574 -               
33575 +
33576                 if (!buffer_is_empty(proc->socket)) {
33577                         unlink(proc->socket->ptr);
33578                 }
33579 -               
33580 +
33581                 close(scgi_fd);
33582 -               
33583 +
33584                 /* reopen socket */
33585                 if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
33586 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
33587 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
33588                                 "socket failed:", strerror(errno));
33589                         return -1;
33590                 }
33591 -               
33592 +
33593                 val = 1;
33594                 if (setsockopt(scgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
33595 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
33596 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
33597                                         "socketsockopt failed:", strerror(errno));
33598                         return -1;
33599                 }
33600 -               
33601 +
33602                 /* create socket */
33603                 if (-1 == bind(scgi_fd, scgi_addr, servlen)) {
33604 -                       log_error_write(srv, __FILE__, __LINE__, "sbds", 
33605 -                               "bind failed for:", 
33606 -                               proc->socket, 
33607 -                               proc->port, 
33608 +                       log_error_write(srv, __FILE__, __LINE__, "sbds",
33609 +                               "bind failed for:",
33610 +                               proc->socket,
33611 +                               proc->port,
33612                                 strerror(errno));
33613                         return -1;
33614                 }
33615 -               
33616 +
33617                 if (-1 == listen(scgi_fd, 1024)) {
33618 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
33619 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
33620                                 "listen failed:", strerror(errno));
33621                         return -1;
33622                 }
33623 -               
33624 -#ifdef HAVE_FORK       
33625 +
33626 +#ifdef HAVE_FORK
33627                 switch ((child = fork())) {
33628                 case 0: {
33629                         buffer *b;
33630                         size_t i = 0;
33631                         int fd = 0;
33632                         char_array env;
33633 -                       
33634 -                       
33635 +
33636 +
33637                         /* create environment */
33638                         env.ptr = NULL;
33639                         env.size = 0;
33640                         env.used = 0;
33641 -                       
33642 +
33643                         /* we don't need the client socket */
33644                         for (fd = 3; fd < 256; fd++) {
33645                                 if (fd != 2 && fd != scgi_fd) close(fd);
33646                         }
33647 -                       
33648 +
33649                         /* build clean environment */
33650                         if (host->bin_env_copy->used) {
33651                                 for (i = 0; i < host->bin_env_copy->used; i++) {
33652                                         data_string *ds = (data_string *)host->bin_env_copy->data[i];
33653                                         char *ge;
33654 -                                       
33655 +
33656                                         if (NULL != (ge = getenv(ds->value->ptr))) {
33657                                                 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
33658                                         }
33659 @@ -772,44 +760,44 @@
33660                         } else {
33661                                 for (i = 0; environ[i]; i++) {
33662                                         char *eq;
33663 -                                       
33664 +
33665                                         if (NULL != (eq = strchr(environ[i], '='))) {
33666                                                 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
33667                                         }
33668                                 }
33669                         }
33670 -                       
33671 +
33672                         /* create environment */
33673                         for (i = 0; i < host->bin_env->used; i++) {
33674                                 data_string *ds = (data_string *)host->bin_env->data[i];
33675 -                               
33676 +
33677                                 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
33678                         }
33679 -                       
33680 +
33681                         for (i = 0; i < env.used; i++) {
33682                                 /* search for PHP_FCGI_CHILDREN */
33683                                 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
33684                         }
33685 -                       
33686 +
33687                         /* not found, add a default */
33688                         if (i == env.used) {
33689                                 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
33690                         }
33691 -                       
33692 +
33693                         env.ptr[env.used] = NULL;
33694 -                       
33695 +
33696                         b = buffer_init();
33697                         buffer_copy_string(b, "exec ");
33698                         buffer_append_string_buffer(b, host->bin_path);
33699 -                       
33700 +
33701                         /* exec the cgi */
33702                         execle("/bin/sh", "sh", "-c", b->ptr, NULL, env.ptr);
33703 -                       
33704 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
33705 +
33706 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
33707                                         "execl failed for:", host->bin_path, strerror(errno));
33708 -                       
33709 +
33710                         exit(errno);
33711 -                       
33712 +
33713                         break;
33714                 }
33715                 case -1:
33716 @@ -817,32 +805,32 @@
33717                         break;
33718                 default:
33719                         /* father */
33720 -                       
33721 +
33722                         /* wait */
33723                         select(0, NULL, NULL, NULL, &tv);
33724 -                       
33725 +
33726                         switch (waitpid(child, &status, WNOHANG)) {
33727                         case 0:
33728                                 /* child still running after timeout, good */
33729                                 break;
33730                         case -1:
33731                                 /* no PID found ? should never happen */
33732 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
33733 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
33734                                                 "pid not found:", strerror(errno));
33735                                 return -1;
33736                         default:
33737                                 /* the child should not terminate at all */
33738                                 if (WIFEXITED(status)) {
33739 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
33740 -                                                       "child exited (is this a SCGI binary ?):", 
33741 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
33742 +                                                       "child exited (is this a SCGI binary ?):",
33743                                                         WEXITSTATUS(status));
33744                                 } else if (WIFSIGNALED(status)) {
33745 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
33746 -                                                       "child signaled:", 
33747 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
33748 +                                                       "child signaled:",
33749                                                         WTERMSIG(status));
33750                                 } else {
33751 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
33752 -                                                       "child died somehow:", 
33753 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
33754 +                                                       "child died somehow:",
33755                                                         status);
33756                                 }
33757                                 return -1;
33758 @@ -852,26 +840,26 @@
33759                         proc->pid = child;
33760                         proc->last_used = srv->cur_ts;
33761                         proc->is_local = 1;
33762 -                                               
33763 +
33764                         break;
33765                 }
33766  #endif
33767         } else {
33768                 proc->is_local = 0;
33769                 proc->pid = 0;
33770 -               
33771 +
33772                 if (p->conf.debug) {
33773                         log_error_write(srv, __FILE__, __LINE__, "sb",
33774                                         "(debug) socket is already used, won't spawn:",
33775                                         proc->socket);
33776                 }
33777         }
33778 -       
33779 +
33780         proc->state = PROC_STATE_RUNNING;
33781         host->active_procs++;
33782 -       
33783 +
33784         close(scgi_fd);
33785 -       
33786 +
33787         return 0;
33788  }
33789  
33790 @@ -880,89 +868,89 @@
33791         plugin_data *p = p_d;
33792         data_unset *du;
33793         size_t i = 0;
33794 -       
33795 -       config_values_t cv[] = { 
33796 +
33797 +       config_values_t cv[] = {
33798                 { "scgi.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
33799                 { "scgi.debug",               NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
33800                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
33801         };
33802 -       
33803 +
33804         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
33805 -       
33806 +
33807         for (i = 0; i < srv->config_context->used; i++) {
33808                 plugin_config *s;
33809                 array *ca;
33810 -               
33811 +
33812                 s = malloc(sizeof(plugin_config));
33813                 s->exts          = scgi_extensions_init();
33814                 s->debug         = 0;
33815 -               
33816 +
33817                 cv[0].destination = s->exts;
33818                 cv[1].destination = &(s->debug);
33819 -               
33820 +
33821                 p->config_storage[i] = s;
33822                 ca = ((data_config *)srv->config_context->data[i])->value;
33823 -       
33824 +
33825                 if (0 != config_insert_values_global(srv, ca, cv)) {
33826                         return HANDLER_ERROR;
33827                 }
33828 -               
33829 -               /* 
33830 +
33831 +               /*
33832                  * <key> = ( ... )
33833                  */
33834 -               
33835 +
33836                 if (NULL != (du = array_get_element(ca, "scgi.server"))) {
33837                         size_t j;
33838                         data_array *da = (data_array *)du;
33839 -                       
33840 +
33841                         if (du->type != TYPE_ARRAY) {
33842 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
33843 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
33844                                                 "unexpected type for key: ", "scgi.server", "array of strings");
33845 -                               
33846 +
33847                                 return HANDLER_ERROR;
33848                         }
33849 -                       
33850 -                       
33851 -                       /* 
33852 -                        * scgi.server = ( "<ext>" => ( ... ), 
33853 +
33854 +
33855 +                       /*
33856 +                        * scgi.server = ( "<ext>" => ( ... ),
33857                          *                    "<ext>" => ( ... ) )
33858                          */
33859 -                       
33860 +
33861                         for (j = 0; j < da->value->used; j++) {
33862                                 size_t n;
33863                                 data_array *da_ext = (data_array *)da->value->data[j];
33864 -                               
33865 +
33866                                 if (da->value->data[j]->type != TYPE_ARRAY) {
33867 -                                       log_error_write(srv, __FILE__, __LINE__, "sssbs", 
33868 -                                                       "unexpected type for key: ", "scgi.server", 
33869 +                                       log_error_write(srv, __FILE__, __LINE__, "sssbs",
33870 +                                                       "unexpected type for key: ", "scgi.server",
33871                                                         "[", da->value->data[j]->key, "](string)");
33872 -                                       
33873 +
33874                                         return HANDLER_ERROR;
33875                                 }
33876 -                               
33877 -                               /* 
33878 -                                * da_ext->key == name of the extension 
33879 +
33880 +                               /*
33881 +                                * da_ext->key == name of the extension
33882                                  */
33883 -                               
33884 -                               /* 
33885 -                                * scgi.server = ( "<ext>" => 
33886 -                                *                     ( "<host>" => ( ... ), 
33887 +
33888 +                               /*
33889 +                                * scgi.server = ( "<ext>" =>
33890 +                                *                     ( "<host>" => ( ... ),
33891                                  *                       "<host>" => ( ... )
33892 -                                *                     ), 
33893 +                                *                     ),
33894                                  *                    "<ext>" => ... )
33895                                  */
33896 -                                       
33897 +
33898                                 for (n = 0; n < da_ext->value->used; n++) {
33899                                         data_array *da_host = (data_array *)da_ext->value->data[n];
33900 -                                       
33901 +
33902                                         scgi_extension_host *df;
33903 -                                       
33904 -                                       config_values_t fcv[] = { 
33905 +
33906 +                                       config_values_t fcv[] = {
33907                                                 { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
33908                                                 { "docroot",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
33909                                                 { "socket",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
33910                                                 { "bin-path",          NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
33911 -                                               
33912 +
33913                                                 { "check-local",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 4 */
33914                                                 { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 5 */
33915                                                 { "min-procs-not-working",         NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 7 this is broken for now */
33916 @@ -970,37 +958,37 @@
33917                                                 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 8 */
33918                                                 { "idle-timeout",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 9 */
33919                                                 { "disable-time",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 10 */
33920 -                                               
33921 +
33922                                                 { "bin-environment",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 11 */
33923                                                 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },     /* 12 */
33924 -                                               
33925 -                                               
33926 +
33927 +
33928                                                 { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
33929                                         };
33930 -                                       
33931 +
33932                                         if (da_host->type != TYPE_ARRAY) {
33933 -                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS", 
33934 -                                                               "unexpected type for key:", 
33935 -                                                               "scgi.server", 
33936 +                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS",
33937 +                                                               "unexpected type for key:",
33938 +                                                               "scgi.server",
33939                                                                 "[", da_host->key, "](string)");
33940 -                                               
33941 +
33942                                                 return HANDLER_ERROR;
33943                                         }
33944 -                                       
33945 +
33946                                         df = scgi_host_init();
33947 -                                       
33948 +
33949                                         df->check_local  = 1;
33950                                         df->min_procs    = 4;
33951                                         df->max_procs    = 4;
33952                                         df->max_load_per_proc = 1;
33953                                         df->idle_timeout = 60;
33954                                         df->disable_time = 60;
33955 -                                       
33956 +
33957                                         fcv[0].destination = df->host;
33958                                         fcv[1].destination = df->docroot;
33959                                         fcv[2].destination = df->unixsocket;
33960                                         fcv[3].destination = df->bin_path;
33961 -                                       
33962 +
33963                                         fcv[4].destination = &(df->check_local);
33964                                         fcv[5].destination = &(df->port);
33965                                         fcv[6].destination = &(df->min_procs);
33966 @@ -1008,47 +996,47 @@
33967                                         fcv[8].destination = &(df->max_load_per_proc);
33968                                         fcv[9].destination = &(df->idle_timeout);
33969                                         fcv[10].destination = &(df->disable_time);
33970 -                                       
33971 +
33972                                         fcv[11].destination = df->bin_env;
33973                                         fcv[12].destination = df->bin_env_copy;
33974 -                                       
33975 -                                       
33976 +
33977 +
33978                                         if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
33979                                                 return HANDLER_ERROR;
33980                                         }
33981 -                                                       
33982 -                                       if ((!buffer_is_empty(df->host) || df->port) && 
33983 +
33984 +                                       if ((!buffer_is_empty(df->host) || df->port) &&
33985                                             !buffer_is_empty(df->unixsocket)) {
33986 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
33987 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
33988                                                                 "either host+port or socket");
33989 -                                               
33990 +
33991                                                 return HANDLER_ERROR;
33992                                         }
33993 -                                       
33994 +
33995                                         if (!buffer_is_empty(df->unixsocket)) {
33996                                                 /* unix domain socket */
33997 -                                               
33998 +
33999                                                 if (df->unixsocket->used > UNIX_PATH_MAX - 2) {
34000 -                                                       log_error_write(srv, __FILE__, __LINE__, "s", 
34001 +                                                       log_error_write(srv, __FILE__, __LINE__, "s",
34002                                                                         "path of the unixdomain socket is too large");
34003                                                         return HANDLER_ERROR;
34004                                                 }
34005                                         } else {
34006                                                 /* tcp/ip */
34007 -                                               
34008 -                                               if (buffer_is_empty(df->host) && 
34009 +
34010 +                                               if (buffer_is_empty(df->host) &&
34011                                                     buffer_is_empty(df->bin_path)) {
34012 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs", 
34013 -                                                                       "missing key (string):", 
34014 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs",
34015 +                                                                       "missing key (string):",
34016                                                                         da->key,
34017                                                                         da_ext->key,
34018                                                                         da_host->key,
34019                                                                         "host");
34020 -                                                       
34021 +
34022                                                         return HANDLER_ERROR;
34023                                                 } else if (df->port == 0) {
34024 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs", 
34025 -                                                                       "missing key (short):", 
34026 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs",
34027 +                                                                       "missing key (short):",
34028                                                                         da->key,
34029                                                                         da_ext->key,
34030                                                                         da_host->key,
34031 @@ -1056,14 +1044,14 @@
34032                                                         return HANDLER_ERROR;
34033                                                 }
34034                                         }
34035 -                                               
34036 -                                       if (!buffer_is_empty(df->bin_path)) { 
34037 +
34038 +                                       if (!buffer_is_empty(df->bin_path)) {
34039                                                 /* a local socket + self spawning */
34040                                                 size_t pno;
34041 -                                               
34042 +
34043                                                 if (df->min_procs > df->max_procs) df->max_procs = df->min_procs;
34044                                                 if (df->max_load_per_proc < 1) df->max_load_per_proc = 0;
34045 -                                               
34046 +
34047                                                 if (s->debug) {
34048                                                         log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
34049                                                                         "--- scgi spawning local",
34050 @@ -1073,7 +1061,7 @@
34051                                                                         "\n\tmin-procs:", df->min_procs,
34052                                                                         "\n\tmax-procs:", df->max_procs);
34053                                                 }
34054 -                                               
34055 +
34056                                                 for (pno = 0; pno < df->min_procs; pno++) {
34057                                                         scgi_proc *proc;
34058  
34059 @@ -1088,7 +1076,7 @@
34060                                                                 buffer_append_string(proc->socket, "-");
34061                                                                 buffer_append_long(proc->socket, pno);
34062                                                         }
34063 -                                                       
34064 +
34065                                                         if (s->debug) {
34066                                                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
34067                                                                                 "--- scgi spawning",
34068 @@ -1096,53 +1084,53 @@
34069                                                                                 "\n\tsocket", df->unixsocket,
34070                                                                                 "\n\tcurrent:", pno, "/", df->min_procs);
34071                                                         }
34072 -                                                       
34073 +
34074                                                         if (scgi_spawn_connection(srv, p, df, proc)) {
34075                                                                 log_error_write(srv, __FILE__, __LINE__, "s",
34076                                                                                 "[ERROR]: spawning fcgi failed.");
34077                                                                 return HANDLER_ERROR;
34078                                                         }
34079 -                                                       
34080 +
34081                                                         proc->next = df->first;
34082                                                         if (df->first)  df->first->prev = proc;
34083 -                                                       
34084 +
34085                                                         df->first = proc;
34086                                                 }
34087                                         } else {
34088                                                 scgi_proc *fp;
34089 -                                               
34090 +
34091                                                 fp = scgi_process_init();
34092                                                 fp->id = df->num_procs++;
34093                                                 df->max_id++;
34094                                                 df->active_procs++;
34095                                                 fp->state = PROC_STATE_RUNNING;
34096 -                                               
34097 +
34098                                                 if (buffer_is_empty(df->unixsocket)) {
34099                                                         fp->port = df->port;
34100                                                 } else {
34101                                                         buffer_copy_string_buffer(fp->socket, df->unixsocket);
34102                                                 }
34103 -                                               
34104 +
34105                                                 df->first = fp;
34106 -                                               
34107 +
34108                                                 df->min_procs = 1;
34109                                                 df->max_procs = 1;
34110                                         }
34111 -                                       
34112 +
34113                                         /* if extension already exists, take it */
34114                                         scgi_extension_insert(s->exts, da_ext->key, df);
34115                                 }
34116                         }
34117                 }
34118         }
34119 -       
34120 +
34121         return HANDLER_GO_ON;
34122  }
34123  
34124  static int scgi_set_state(server *srv, handler_ctx *hctx, scgi_connection_state_t state) {
34125         hctx->state = state;
34126         hctx->state_timestamp = srv->cur_ts;
34127 -       
34128 +
34129         return 0;
34130  }
34131  
34132 @@ -1150,35 +1138,35 @@
34133  void scgi_connection_cleanup(server *srv, handler_ctx *hctx) {
34134         plugin_data *p;
34135         connection  *con;
34136 -       
34137 +
34138         if (NULL == hctx) return;
34139 -       
34140 +
34141         p    = hctx->plugin_data;
34142         con  = hctx->remote_conn;
34143 -       
34144 +
34145         if (con->mode != p->id) {
34146 -               WP();
34147                 return;
34148         }
34149 -       
34150 -       if (hctx->fd != -1) {
34151 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
34152 -               fdevent_unregister(srv->ev, hctx->fd);
34153 -               close(hctx->fd);
34154 +
34155 +       if (hctx->sock->fd != -1) {
34156 +               fdevent_event_del(srv->ev, hctx->sock);
34157 +               fdevent_unregister(srv->ev, hctx->sock);
34158 +               closesocket(hctx->sock->fd);
34159 +               hctx->sock->fd = -1;
34160                 srv->cur_fds--;
34161         }
34162 -       
34163 +
34164         if (hctx->host && hctx->proc) {
34165                 hctx->host->load--;
34166 -               
34167 +
34168                 if (hctx->got_proc) {
34169                         /* after the connect the process gets a load */
34170                         hctx->proc->load--;
34171 -                       
34172 +
34173                         if (p->conf.debug) {
34174                                 log_error_write(srv, __FILE__, __LINE__, "sddb",
34175 -                                               "release proc:", 
34176 -                                               hctx->fd,
34177 +                                               "release proc:",
34178 +                                               hctx->sock->fd,
34179                                                 hctx->proc->pid, hctx->proc->socket);
34180                         }
34181                 }
34182 @@ -1186,87 +1174,87 @@
34183                 scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
34184         }
34185  
34186 -       
34187 +
34188         handler_ctx_free(hctx);
34189 -       con->plugin_ctx[p->id] = NULL;  
34190 +       con->plugin_ctx[p->id] = NULL;
34191  }
34192  
34193  static int scgi_reconnect(server *srv, handler_ctx *hctx) {
34194         plugin_data *p    = hctx->plugin_data;
34195 -       
34196 -       /* child died 
34197 -        * 
34198 -        * 1. 
34199 -        * 
34200 +
34201 +       /* child died
34202 +        *
34203 +        * 1.
34204 +        *
34205          * connect was ok, connection was accepted
34206          * but the php accept loop checks after the accept if it should die or not.
34207 -        * 
34208 -        * if yes we can only detect it at a write() 
34209 -        * 
34210 +        *
34211 +        * if yes we can only detect it at a write()
34212 +        *
34213          * next step is resetting this attemp and setup a connection again
34214 -        * 
34215 +        *
34216          * if we have more then 5 reconnects for the same request, die
34217 -        * 
34218 -        * 2. 
34219 -        * 
34220 +        *
34221 +        * 2.
34222 +        *
34223          * we have a connection but the child died by some other reason
34224 -        * 
34225 +        *
34226          */
34227 -       
34228 -       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
34229 -       fdevent_unregister(srv->ev, hctx->fd);
34230 -       close(hctx->fd);
34231 +
34232 +       fdevent_event_del(srv->ev, hctx->sock);
34233 +       fdevent_unregister(srv->ev, hctx->sock);
34234 +       closesocket(hctx->sock->fd);
34235         srv->cur_fds--;
34236 -       
34237 -       scgi_set_state(srv, hctx, FCGI_STATE_INIT);
34238 -       
34239 +
34240 +       scgi_set_state(srv, hctx, SCGI_STATE_INIT);
34241 +
34242         hctx->request_id = 0;
34243         hctx->reconnects++;
34244 -       
34245 +
34246         if (p->conf.debug) {
34247                 log_error_write(srv, __FILE__, __LINE__, "sddb",
34248 -                               "release proc:", 
34249 -                               hctx->fd,
34250 +                               "release proc:",
34251 +                               hctx->sock->fd,
34252                                 hctx->proc->pid, hctx->proc->socket);
34253         }
34254 -       
34255 +
34256         hctx->proc->load--;
34257         scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
34258 -       
34259 +
34260         return 0;
34261  }
34262  
34263  
34264  static handler_t scgi_connection_reset(server *srv, connection *con, void *p_d) {
34265         plugin_data *p = p_d;
34266 -       
34267 +
34268         scgi_connection_cleanup(srv, con->plugin_ctx[p->id]);
34269 -       
34270 +
34271         return HANDLER_GO_ON;
34272  }
34273  
34274  
34275  static int scgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
34276         size_t len;
34277 -       
34278 +
34279         if (!key || !val) return -1;
34280 -       
34281 +
34282         len = key_len + val_len + 2;
34283 -       
34284 +
34285         buffer_prepare_append(env, len);
34286  
34287 -       /* include the NUL */   
34288 +       /* include the NUL */
34289         memcpy(env->ptr + env->used, key, key_len + 1);
34290         env->used += key_len + 1;
34291         memcpy(env->ptr + env->used, val, val_len + 1);
34292         env->used += val_len + 1;
34293 -       
34294 +
34295         return 0;
34296  }
34297  
34298  
34299  /**
34300 - * 
34301 + *
34302   * returns
34303   *   -1 error
34304   *    0 connected
34305 @@ -1280,24 +1268,21 @@
34306         struct sockaddr_un scgi_addr_un;
34307  #endif
34308         socklen_t servlen;
34309 -       
34310 +
34311         scgi_extension_host *host = hctx->host;
34312         scgi_proc *proc   = hctx->proc;
34313 -       int scgi_fd       = hctx->fd;
34314 -       
34315 +       int scgi_fd       = hctx->sock->fd;
34316 +
34317         memset(&scgi_addr, 0, sizeof(scgi_addr));
34318 -       
34319 +
34320         if (!buffer_is_empty(proc->socket)) {
34321  #ifdef HAVE_SYS_UN_H
34322                 /* use the unix domain socket */
34323                 scgi_addr_un.sun_family = AF_UNIX;
34324                 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
34325 -#ifdef SUN_LEN
34326 +               
34327                 servlen = SUN_LEN(&scgi_addr_un);
34328 -#else
34329 -               /* stevens says: */
34330 -               servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
34331 -#endif
34332 +
34333                 scgi_addr = (struct sockaddr *) &scgi_addr_un;
34334  #else
34335                 return -1;
34336 @@ -1305,105 +1290,105 @@
34337         } else {
34338                 scgi_addr_in.sin_family = AF_INET;
34339                 if (0 == inet_aton(host->host->ptr, &(scgi_addr_in.sin_addr))) {
34340 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
34341 -                                       "converting IP-adress failed for", host->host, 
34342 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
34343 +                                       "converting IP-adress failed for", host->host,
34344                                         "\nBe sure to specify an IP address here");
34345 -                       
34346 +
34347                         return -1;
34348                 }
34349                 scgi_addr_in.sin_port = htons(proc->port);
34350                 servlen = sizeof(scgi_addr_in);
34351 -               
34352 +
34353                 scgi_addr = (struct sockaddr *) &scgi_addr_in;
34354         }
34355 -       
34356 +
34357         if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
34358 -               if (errno == EINPROGRESS || 
34359 +               if (errno == EINPROGRESS ||
34360                     errno == EALREADY ||
34361                     errno == EINTR) {
34362                         if (hctx->conf.debug) {
34363 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
34364 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
34365                                                 "connect delayed, will continue later:", scgi_fd);
34366                         }
34367 -                       
34368 +
34369                         return 1;
34370                 } else {
34371 -                       log_error_write(srv, __FILE__, __LINE__, "sdsddb", 
34372 -                                       "connect failed:", scgi_fd, 
34373 +                       log_error_write(srv, __FILE__, __LINE__, "sdsddb",
34374 +                                       "connect failed:", scgi_fd,
34375                                         strerror(errno), errno,
34376                                         proc->port, proc->socket);
34377  
34378                         if (errno == EAGAIN) {
34379                                 /* this is Linux only */
34380 -                               
34381 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
34382 +
34383 +                               log_error_write(srv, __FILE__, __LINE__, "s",
34384                                                 "If this happend on Linux: You have been run out of local ports. "
34385                                                 "Check the manual, section Performance how to handle this.");
34386 -                       } 
34387 -                       
34388 +                       }
34389 +
34390                         return -1;
34391                 }
34392         }
34393         if (hctx->conf.debug > 1) {
34394 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
34395 +               log_error_write(srv, __FILE__, __LINE__, "sd",
34396                                 "connect succeeded: ", scgi_fd);
34397         }
34398  
34399  
34400 -       
34401 +
34402         return 0;
34403  }
34404  
34405  static int scgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
34406         size_t i;
34407 -       
34408 +
34409         for (i = 0; i < con->request.headers->used; i++) {
34410                 data_string *ds;
34411 -               
34412 +
34413                 ds = (data_string *)con->request.headers->data[i];
34414 -               
34415 +
34416                 if (ds->value->used && ds->key->used) {
34417                         size_t j;
34418                         buffer_reset(srv->tmp_buf);
34419 -                       
34420 +
34421                         if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
34422                                 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
34423                                 srv->tmp_buf->used--;
34424                         }
34425 -                       
34426 +
34427                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
34428                         for (j = 0; j < ds->key->used - 1; j++) {
34429 -                               srv->tmp_buf->ptr[srv->tmp_buf->used++] = 
34430 -                                       light_isalpha(ds->key->ptr[j]) ? 
34431 +                               srv->tmp_buf->ptr[srv->tmp_buf->used++] =
34432 +                                       light_isalpha(ds->key->ptr[j]) ?
34433                                         ds->key->ptr[j] & ~32 : '_';
34434                         }
34435                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
34436 -                       
34437 +
34438                         scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
34439                 }
34440         }
34441 -       
34442 +
34443         for (i = 0; i < con->environment->used; i++) {
34444                 data_string *ds;
34445 -               
34446 +
34447                 ds = (data_string *)con->environment->data[i];
34448 -               
34449 +
34450                 if (ds->value->used && ds->key->used) {
34451                         size_t j;
34452                         buffer_reset(srv->tmp_buf);
34453 -                       
34454 +
34455                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
34456                         for (j = 0; j < ds->key->used - 1; j++) {
34457 -                               srv->tmp_buf->ptr[srv->tmp_buf->used++] = 
34458 -                                       isalpha((unsigned char)ds->key->ptr[j]) ? 
34459 +                               srv->tmp_buf->ptr[srv->tmp_buf->used++] =
34460 +                                       isalpha((unsigned char)ds->key->ptr[j]) ?
34461                                         toupper((unsigned char)ds->key->ptr[j]) : '_';
34462                         }
34463                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
34464 -                       
34465 +
34466                         scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
34467                 }
34468         }
34469 -       
34470 +
34471         return 0;
34472  }
34473  
34474 @@ -1415,20 +1400,20 @@
34475         char b2[INET6_ADDRSTRLEN + 1];
34476  #endif
34477         buffer *b;
34478 -       
34479 +
34480         plugin_data *p    = hctx->plugin_data;
34481         scgi_extension_host *host= hctx->host;
34482  
34483         connection *con   = hctx->remote_conn;
34484         server_socket *srv_sock = con->srv_socket;
34485 -       
34486 +
34487         sock_addr our_addr;
34488         socklen_t our_addr_len;
34489 -       
34490 +
34491         buffer_prepare_copy(p->scgi_env, 1024);
34492  
34493         /* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
34494 -               
34495 +
34496         /* request.content_length < SSIZE_MAX, see request.c */
34497         ltostr(buf, con->request.content_length);
34498         scgi_env_add(p->scgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
34499 @@ -1436,13 +1421,13 @@
34500  
34501  
34502         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
34503 -       
34504 +
34505         if (con->server_name->used) {
34506                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
34507         } else {
34508  #ifdef HAVE_IPV6
34509 -               s = inet_ntop(srv_sock->addr.plain.sa_family, 
34510 -                             srv_sock->addr.plain.sa_family == AF_INET6 ? 
34511 +               s = inet_ntop(srv_sock->addr.plain.sa_family,
34512 +                             srv_sock->addr.plain.sa_family == AF_INET6 ?
34513                               (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
34514                               (const void *) &(srv_sock->addr.ipv4.sin_addr),
34515                               b2, sizeof(b2)-1);
34516 @@ -1451,47 +1436,47 @@
34517  #endif
34518                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
34519         }
34520 -       
34521 +
34522         scgi_env_add(p->scgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
34523 -       
34524 -       ltostr(buf, 
34525 +
34526 +       ltostr(buf,
34527  #ifdef HAVE_IPV6
34528                ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
34529  #else
34530                ntohs(srv_sock->addr.ipv4.sin_port)
34531  #endif
34532                );
34533 -       
34534 +
34535         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
34536 -       
34537 +
34538         /* get the server-side of the connection to the client */
34539         our_addr_len = sizeof(our_addr);
34540 -       
34541 -       if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
34542 +
34543 +       if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
34544                 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
34545         } else {
34546                 s = inet_ntop_cache_get_ip(srv, &(our_addr));
34547         }
34548         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
34549 -       
34550 -       ltostr(buf, 
34551 +
34552 +       ltostr(buf,
34553  #ifdef HAVE_IPV6
34554                ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
34555  #else
34556                ntohs(con->dst_addr.ipv4.sin_port)
34557  #endif
34558                );
34559 -       
34560 +
34561         scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
34562 -       
34563 +
34564         s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
34565         scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
34566 -       
34567 +
34568         if (!buffer_is_empty(con->authed_user)) {
34569                 scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_USER"),
34570                              CONST_BUF_LEN(con->authed_user));
34571         }
34572 -       
34573 +
34574  
34575         /*
34576          * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
34577 @@ -1500,12 +1485,12 @@
34578          */
34579  
34580         scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
34581 -               
34582 +
34583         if (!buffer_is_empty(con->request.pathinfo)) {
34584                 scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
34585 -               
34586 +
34587                 /* PATH_TRANSLATED is only defined if PATH_INFO is set */
34588 -               
34589 +
34590                 if (!buffer_is_empty(host->docroot)) {
34591                         buffer_copy_string_buffer(p->path, host->docroot);
34592                 } else {
34593 @@ -1526,19 +1511,19 @@
34594          */
34595  
34596         if (!buffer_is_empty(host->docroot)) {
34597 -               /* 
34598 -                * rewrite SCRIPT_FILENAME 
34599 -                * 
34600 +               /*
34601 +                * rewrite SCRIPT_FILENAME
34602 +                *
34603                  */
34604 -               
34605 +
34606                 buffer_copy_string_buffer(p->path, host->docroot);
34607                 buffer_append_string_buffer(p->path, con->uri.path);
34608 -               
34609 +
34610                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
34611                 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
34612         } else {
34613                 buffer_copy_string_buffer(p->path, con->physical.path);
34614 -               
34615 +
34616                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
34617                 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
34618         }
34619 @@ -1551,30 +1536,30 @@
34620         } else {
34621                 scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
34622         }
34623 -       
34624 +
34625         s = get_http_method_name(con->request.http_method);
34626         scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
34627         scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
34628         s = get_http_version_name(con->request.http_version);
34629         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
34630 -       
34631 +
34632  #ifdef USE_OPENSSL
34633         if (srv_sock->is_ssl) {
34634                 scgi_env_add(p->scgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
34635         }
34636  #endif
34637 -       
34638 +
34639         scgi_env_add_request_headers(srv, con, p);
34640  
34641         b = chunkqueue_get_append_buffer(hctx->wb);
34642 -       
34643 +
34644         buffer_append_long(b, p->scgi_env->used);
34645         buffer_append_string_len(b, CONST_STR_LEN(":"));
34646         buffer_append_string_len(b, (const char *)p->scgi_env->ptr, p->scgi_env->used);
34647         buffer_append_string_len(b, CONST_STR_LEN(","));
34648  
34649         hctx->wb->bytes_in += b->used - 1;
34650 -       
34651 +
34652         if (con->request.content_length) {
34653                 chunkqueue *req_cq = con->request_content_queue;
34654                 chunk *req_c;
34655 @@ -1587,7 +1572,7 @@
34656  
34657                         /* we announce toWrite octects
34658                          * now take all the request_content chunk that we need to fill this request
34659 -                        * */   
34660 +                        * */
34661  
34662                         switch (req_c->type) {
34663                         case FILE_CHUNK:
34664 @@ -1615,293 +1600,170 @@
34665  
34666                                 req_c->offset += weHave;
34667                                 req_cq->bytes_out += weHave;
34668 -                               
34669 +
34670                                 hctx->wb->bytes_in += weHave;
34671  
34672                                 break;
34673                         default:
34674                                 break;
34675                         }
34676 -                       
34677 +
34678                         offset += weHave;
34679                 }
34680         }
34681 -       
34682 +
34683  #if 0
34684         for (i = 0; i < hctx->write_buffer->used; i++) {
34685                 fprintf(stderr, "%02x ", hctx->write_buffer->ptr[i]);
34686                 if ((i+1) % 16 == 0) {
34687                         size_t j;
34688                         for (j = i-15; j <= i; j++) {
34689 -                               fprintf(stderr, "%c", 
34690 +                               fprintf(stderr, "%c",
34691                                         isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
34692                         }
34693                         fprintf(stderr, "\n");
34694                 }
34695         }
34696  #endif
34697 -       
34698 -       return 0;
34699 -}
34700  
34701 -static int scgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
34702 -       char *ns;
34703 -       const char *s;
34704 -       int line = 0;
34705 -       
34706 -       UNUSED(srv);
34707 -       
34708 -       buffer_copy_string_buffer(p->parse_response, in);
34709 -       
34710 -       for (s = p->parse_response->ptr; 
34711 -            NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n'))); 
34712 -            s = ns + (eol == EOL_RN ? 2 : 1), line++) {
34713 -               const char *key, *value;
34714 -               int key_len;
34715 -               data_string *ds;
34716 -               
34717 -               ns[0] = '\0';
34718 -               
34719 -               if (line == 0 && 
34720 -                   0 == strncmp(s, "HTTP/1.", 7)) {
34721 -                       /* non-parsed header ... we parse them anyway */
34722 -                       
34723 -                       if ((s[7] == '1' ||
34724 -                            s[7] == '0') &&
34725 -                           s[8] == ' ') {
34726 -                               int status;
34727 -                               /* after the space should be a status code for us */
34728 -                               
34729 -                               status = strtol(s+9, NULL, 10);
34730 -                               
34731 -                               if (con->http_status >= 100 &&
34732 -                                   con->http_status < 1000) {
34733 -                                       /* we expected 3 digits and didn't got them */
34734 -                                       con->parsed_response |= HTTP_STATUS;
34735 -                                       con->http_status = status;
34736 -                               }
34737 -                       }
34738 -               } else {
34739 -               
34740 -                       key = s;
34741 -                       if (NULL == (value = strchr(s, ':'))) {
34742 -                               /* we expect: "<key>: <value>\r\n" */
34743 -                               continue;
34744 -                       }
34745 -                       
34746 -                       key_len = value - key;
34747 -                       value += 1;
34748 -                       
34749 -                       /* skip LWS */
34750 -                       while (*value == ' ' || *value == '\t') value++;
34751 -                       
34752 -                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
34753 -                               ds = data_response_init();
34754 -                       }
34755 -                       buffer_copy_string_len(ds->key, key, key_len);
34756 -                       buffer_copy_string(ds->value, value);
34757 -                       
34758 -                       array_insert_unique(con->response.headers, (data_unset *)ds);
34759 -                       
34760 -                       switch(key_len) {
34761 -                       case 4:
34762 -                               if (0 == strncasecmp(key, "Date", key_len)) {
34763 -                                       con->parsed_response |= HTTP_DATE;
34764 -                               }
34765 -                               break;
34766 -                       case 6:
34767 -                               if (0 == strncasecmp(key, "Status", key_len)) {
34768 -                                       con->http_status = strtol(value, NULL, 10);
34769 -                                       con->parsed_response |= HTTP_STATUS;
34770 -                               }
34771 -                               break;
34772 -                       case 8:
34773 -                               if (0 == strncasecmp(key, "Location", key_len)) {
34774 -                                       con->parsed_response |= HTTP_LOCATION;
34775 -                               }
34776 -                               break;
34777 -                       case 10:
34778 -                               if (0 == strncasecmp(key, "Connection", key_len)) {
34779 -                                       con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
34780 -                                       con->parsed_response |= HTTP_CONNECTION;
34781 -                               }
34782 -                               break;
34783 -                       case 14:
34784 -                               if (0 == strncasecmp(key, "Content-Length", key_len)) {
34785 -                                       con->response.content_length = strtol(value, NULL, 10);
34786 -                                       con->parsed_response |= HTTP_CONTENT_LENGTH;
34787 -                               }
34788 -                               break;
34789 -                       default:
34790 -                               break;
34791 -                       }
34792 -               }
34793 -       }
34794 -       
34795 -       /* CGI/1.1 rev 03 - 7.2.1.2 */
34796 -       if ((con->parsed_response & HTTP_LOCATION) &&
34797 -           !(con->parsed_response & HTTP_STATUS)) {
34798 -               con->http_status = 302;
34799 -       }
34800 -       
34801         return 0;
34802  }
34803  
34804 -
34805  static int scgi_demux_response(server *srv, handler_ctx *hctx) {
34806         plugin_data *p    = hctx->plugin_data;
34807         connection  *con  = hctx->remote_conn;
34808 -       
34809 -       while(1) {
34810 -               int n;
34811 -               
34812 -               buffer_prepare_copy(hctx->response, 1024);
34813 -               if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
34814 -                       if (errno == EAGAIN || errno == EINTR) {
34815 -                               /* would block, wait for signal */
34816 -                               return 0;
34817 -                       }
34818 -                       /* error */
34819 -                       log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
34820 -                       return -1;
34821 -               }
34822 -               
34823 -               if (n == 0) {
34824 -                       /* read finished */
34825 -                       
34826 -                       con->file_finished = 1;
34827 -                       
34828 -                       /* send final chunk */
34829 -                       http_chunk_append_mem(srv, con, NULL, 0);
34830 -                       joblist_append(srv, con);
34831 -                       
34832 +       chunk *c;
34833 +
34834 +       switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
34835 +       case NETWORK_STATUS_SUCCESS:
34836 +               /* we got content */
34837 +               break;
34838 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
34839 +               /* the ioctl will return WAIT_FOR_EVENT on a read */
34840 +               if (0 == con->file_started) return -1;
34841 +       case NETWORK_STATUS_CONNECTION_CLOSE:
34842 +               /* we are done, get out of here */
34843 +               con->file_finished = 1;
34844 +
34845 +               /* close the chunk-queue with a empty chunk */
34846 +
34847 +               return 1;
34848 +       default:
34849 +               /* oops */
34850 +               return -1;
34851 +       }
34852 +
34853 +       /* looks like we got some content
34854 +       *
34855 +       * split off the header from the incoming stream
34856 +       */
34857 +
34858 +       if (hctx->state == SCGI_STATE_RESPONSE_HEADER) {
34859 +               size_t i;
34860 +               int have_content_length = 0;
34861 +
34862 +               http_response_reset(p->resp);
34863 +
34864 +               /* the response header is not fully received yet,
34865 +               *
34866 +               * extract the http-response header from the rb-cq
34867 +               */
34868 +               switch (http_response_parse_cq(hctx->rb, p->resp)) {
34869 +               case PARSE_ERROR:
34870 +                       /* parsing failed */
34871 +
34872 +                       con->http_status = 502; /* Bad Gateway */
34873                         return 1;
34874 -               }
34875 -               
34876 -               hctx->response->ptr[n] = '\0';
34877 -               hctx->response->used = n+1;
34878 -               
34879 -               /* split header from body */
34880 -               
34881 -               if (con->file_started == 0) {
34882 -                       char *c;
34883 -                       int in_header = 0;
34884 -                       int header_end = 0;
34885 -                       int cp, eol = EOL_UNSET;
34886 -                       size_t used = 0;
34887 -                       
34888 -                       buffer_append_string_buffer(hctx->response_header, hctx->response);
34889 -                       
34890 -                       /* nph (non-parsed headers) */
34891 -                       if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
34892 -                       
34893 -                       /* search for the \r\n\r\n or \n\n in the string */
34894 -                       for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
34895 -                               if (*c == ':') in_header = 1;
34896 -                               else if (*c == '\n') {
34897 -                                       if (in_header == 0) {
34898 -                                               /* got a response without a response header */
34899 -                                               
34900 -                                               c = NULL;
34901 -                                               header_end = 1;
34902 -                                               break;
34903 -                                       }
34904 -                                       
34905 -                                       if (eol == EOL_UNSET) eol = EOL_N;
34906 -                                       
34907 -                                       if (*(c+1) == '\n') {
34908 -                                               header_end = 1;
34909 -                                               break;
34910 -                                       }
34911 -                                       
34912 -                               } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
34913 -                                       if (in_header == 0) {
34914 -                                               /* got a response without a response header */
34915 -                                               
34916 -                                               c = NULL;
34917 -                                               header_end = 1;
34918 -                                               break;
34919 -                                       }
34920 -                                       
34921 -                                       if (eol == EOL_UNSET) eol = EOL_RN;
34922 -                                       
34923 -                                       if (used > 3 &&
34924 -                                           *(c+2) == '\r' && 
34925 -                                           *(c+3) == '\n') {
34926 -                                               header_end = 1;
34927 -                                               break;
34928 -                                       }
34929 -                                       
34930 -                                       /* skip the \n */
34931 -                                       c++;
34932 -                                       cp++;
34933 -                                       used--;
34934 +               case PARSE_NEED_MORE:
34935 +                       return 0;
34936 +               case PARSE_SUCCESS:
34937 +                       con->http_status = p->resp->status;
34938 +
34939 +                       chunkqueue_remove_finished_chunks(hctx->rb);
34940 +
34941 +                       /* copy the http-headers */
34942 +                       for (i = 0; i < p->resp->headers->used; i++) {
34943 +                               const char *ign[] = { "Status", "Connection", NULL };
34944 +                               size_t j;
34945 +                               data_string *ds;
34946 +
34947 +                               data_string *header = (data_string *)p->resp->headers->data[i];
34948 +
34949 +                               /* some headers are ignored by default */
34950 +                               for (j = 0; ign[j]; j++) {
34951 +                                       if (0 == strcasecmp(ign[j], header->key->ptr)) break;
34952                                 }
34953 -                       }
34954 -                       
34955 -                       if (header_end) {
34956 -                               if (c == NULL) {
34957 -                                       /* no header, but a body */
34958 -                                       
34959 -                                       if (con->request.http_version == HTTP_VERSION_1_1) {
34960 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34961 -                                       }
34962 -                                       
34963 -                                       http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
34964 -                                       joblist_append(srv, con);
34965 -                               } else {
34966 -                                       size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
34967 -                                       size_t blen = hctx->response_header->used - hlen - 1;
34968 -                               
34969 -                                       /* a small hack: terminate after at the second \r */
34970 -                                       hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
34971 -                                       hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
34972 -                               
34973 -                                       /* parse the response header */
34974 -                                       scgi_response_parse(srv, con, p, hctx->response_header, eol);
34975 -                                       
34976 -                                       /* enable chunked-transfer-encoding */
34977 -                                       if (con->request.http_version == HTTP_VERSION_1_1 &&
34978 -                                           !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
34979 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34980 -                                       }
34981 -                                       
34982 -                                       if ((hctx->response->used != hlen) && blen > 0) {
34983 -                                               http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
34984 -                                               joblist_append(srv, con);
34985 -                                       }
34986 +                               if (ign[j]) continue;
34987 +
34988 +                               if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
34989 +                                       /* CGI/1.1 rev 03 - 7.2.1.2 */
34990 +                                       if (con->http_status == 0) con->http_status = 302;
34991 +                               } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
34992 +                                       have_content_length = 1;
34993                                 }
34994                                 
34995 -                               con->file_started = 1;
34996 +                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
34997 +                                       ds = data_response_init();
34998 +                               }
34999 +                               buffer_copy_string_buffer(ds->key, header->key);
35000 +                               buffer_copy_string_buffer(ds->value, header->value);
35001 +
35002 +                               array_insert_unique(con->response.headers, (data_unset *)ds);
35003                         }
35004 -               } else {
35005 -                       http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
35006 -                       joblist_append(srv, con);
35007 +
35008 +                       con->file_started = 1;
35009 +
35010 +                       if (con->request.http_version == HTTP_VERSION_1_1 &&
35011 +                           !have_content_length) {
35012 +                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
35013 +                       }
35014 +
35015 +                       hctx->state = SCGI_STATE_RESPONSE_CONTENT;
35016 +                       break;
35017                 }
35018 -               
35019 -#if 0          
35020 -               log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
35021 -#endif
35022         }
35023 -       
35024 +
35025 +       /* FIXME: pass the response-header to the other plugins to
35026 +       * setup the filter-queue
35027 +       *
35028 +       * - use next-queue instead of con->write_queue
35029 +       */
35030 +
35031 +       assert(hctx->state == SCGI_STATE_RESPONSE_CONTENT);
35032 +
35033 +       /* FIXME: if we have a content-length or chunked-encoding
35034 +       * handle it.
35035 +       *
35036 +       * for now we wait for EOF on the socket */
35037 +
35038 +       /* copy the content to the next cq */
35039 +       for (c = hctx->rb->first; c; c = c->next) {
35040 +               http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
35041 +
35042 +               c->offset = c->mem->used - 1;
35043 +       }
35044 +
35045 +       chunkqueue_remove_finished_chunks(hctx->rb);
35046 +       joblist_append(srv, con);
35047 +
35048         return 0;
35049  }
35050  
35051  
35052  int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *proc) {
35053         scgi_proc *p;
35054 -       
35055 +
35056         UNUSED(srv);
35057 -       
35058 -       /* we have been the smallest of the current list 
35059 -        * and we want to insert the node sorted as soon 
35060 +
35061 +       /* we have been the smallest of the current list
35062 +        * and we want to insert the node sorted as soon
35063          * possible
35064          *
35065 -        * 1 0 0 0 1 1 1 
35066 -        * |      ^ 
35067 +        * 1 0 0 0 1 1 1
35068 +        * |      ^
35069          * |      |
35070          * +------+
35071 -        * 
35072 +        *
35073          */
35074  
35075         /* nothing to sort, only one element */
35076 @@ -1909,9 +1771,9 @@
35077  
35078         for (p = proc; p->next && p->next->load < proc->load; p = p->next);
35079  
35080 -       /* no need to move something 
35081 +       /* no need to move something
35082          *
35083 -        * 1 2 2 2 3 3 3 
35084 +        * 1 2 2 2 3 3 3
35085          * ^
35086          * |
35087          * +
35088 @@ -1930,16 +1792,16 @@
35089  
35090         if (proc->prev) proc->prev->next = proc->next;
35091         if (proc->next) proc->next->prev = proc->prev;
35092 -       
35093 +
35094         /* proc should be right of p */
35095 -       
35096 +
35097         proc->next = p->next;
35098         proc->prev = p;
35099         if (p->next) p->next->prev = proc;
35100         p->next = proc;
35101  #if 0
35102         for(p = host->first; p; p = p->next) {
35103 -               log_error_write(srv, __FILE__, __LINE__, "dd", 
35104 +               log_error_write(srv, __FILE__, __LINE__, "dd",
35105                                 p->pid, p->load);
35106         }
35107  #else
35108 @@ -1951,21 +1813,21 @@
35109  
35110  int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *proc) {
35111         scgi_proc *p;
35112 -       
35113 +
35114         UNUSED(srv);
35115 -       
35116 -       /* we have been the smallest of the current list 
35117 -        * and we want to insert the node sorted as soon 
35118 +
35119 +       /* we have been the smallest of the current list
35120 +        * and we want to insert the node sorted as soon
35121          * possible
35122          *
35123 -        *  0 0 0 0 1 0 1 
35124 +        *  0 0 0 0 1 0 1
35125          * ^          |
35126          * |          |
35127          * +----------+
35128          *
35129          *
35130          * the basic is idea is:
35131 -        * - the last active scgi process should be still 
35132 +        * - the last active scgi process should be still
35133          *   in ram and is not swapped out yet
35134          * - processes that are not reused will be killed
35135          *   after some time by the trigger-handler
35136 @@ -1975,7 +1837,7 @@
35137          *   ice-cold processes are propably unused since more
35138          *   than 'unused-timeout', are swaped out and won't be
35139          *   reused in the next seconds anyway.
35140 -        * 
35141 +        *
35142          */
35143  
35144         /* nothing to sort, only one element */
35145 @@ -1984,16 +1846,16 @@
35146         for (p = host->first; p != proc && p->load < proc->load; p = p->next);
35147  
35148  
35149 -       /* no need to move something 
35150 +       /* no need to move something
35151          *
35152 -        * 1 2 2 2 3 3 3 
35153 +        * 1 2 2 2 3 3 3
35154          * ^
35155          * |
35156          * +
35157          *
35158          */
35159         if (p == proc) return 0;
35160 -       
35161 +
35162         /* we have to move left. If we are already the first element
35163          * we are done */
35164         if (host->first == proc) return 0;
35165 @@ -2009,9 +1871,9 @@
35166         p->prev = proc;
35167  
35168         if (proc->prev == NULL) host->first = proc;
35169 -#if 0  
35170 +#if 0
35171         for(p = host->first; p; p = p->next) {
35172 -               log_error_write(srv, __FILE__, __LINE__, "dd", 
35173 +               log_error_write(srv, __FILE__, __LINE__, "dd",
35174                                 p->pid, p->load);
35175         }
35176  #else
35177 @@ -2023,41 +1885,42 @@
35178  
35179  static int scgi_restart_dead_procs(server *srv, plugin_data *p, scgi_extension_host *host) {
35180         scgi_proc *proc;
35181 -       
35182 +
35183         for (proc = host->first; proc; proc = proc->next) {
35184                 if (p->conf.debug) {
35185 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdbdddd", 
35186 -                                       "proc:", 
35187 -                                       host->host, proc->port, 
35188 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdbdddd",
35189 +                                       "proc:",
35190 +                                       host->host, proc->port,
35191                                         proc->socket,
35192                                         proc->state,
35193                                         proc->is_local,
35194                                         proc->load,
35195                                         proc->pid);
35196                 }
35197 -               
35198 +
35199                 if (0 == proc->is_local) {
35200 -                       /* 
35201 -                        * external servers might get disabled 
35202 -                        * 
35203 -                        * enable the server again, perhaps it is back again 
35204 +                       /*
35205 +                        * external servers might get disabled
35206 +                        *
35207 +                        * enable the server again, perhaps it is back again
35208                          */
35209 -                       
35210 +
35211                         if ((proc->state == PROC_STATE_DISABLED) &&
35212                             (srv->cur_ts - proc->disable_ts > host->disable_time)) {
35213                                 proc->state = PROC_STATE_RUNNING;
35214                                 host->active_procs++;
35215 -                               
35216 -                               log_error_write(srv, __FILE__, __LINE__,  "sbdb", 
35217 -                                               "fcgi-server re-enabled:", 
35218 -                                               host->host, host->port, 
35219 +
35220 +                               log_error_write(srv, __FILE__, __LINE__,  "sbdb",
35221 +                                               "fcgi-server re-enabled:",
35222 +                                               host->host, host->port,
35223                                                 host->unixsocket);
35224                         }
35225                 } else {
35226                         /* the child should not terminate at all */
35227                         int status;
35228 -                       
35229 +
35230                         if (proc->state == PROC_STATE_DIED_WAIT_FOR_PID) {
35231 +#ifndef _WIN32
35232                                 switch(waitpid(proc->pid, &status, WNOHANG)) {
35233                                 case 0:
35234                                         /* child is still alive */
35235 @@ -2067,33 +1930,34 @@
35236                                 default:
35237                                         if (WIFEXITED(status)) {
35238  #if 0
35239 -                                               log_error_write(srv, __FILE__, __LINE__, "sdsd", 
35240 +                                               log_error_write(srv, __FILE__, __LINE__, "sdsd",
35241                                                                 "child exited, pid:", proc->pid,
35242                                                                 "status:", WEXITSTATUS(status));
35243  #endif
35244                                         } else if (WIFSIGNALED(status)) {
35245 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35246 -                                                               "child signaled:", 
35247 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
35248 +                                                               "child signaled:",
35249                                                                 WTERMSIG(status));
35250                                         } else {
35251 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35252 -                                                               "child died somehow:", 
35253 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
35254 +                                                               "child died somehow:",
35255                                                                 status);
35256                                         }
35257 -                                       
35258 +
35259                                         proc->state = PROC_STATE_DIED;
35260                                         break;
35261                                 }
35262 +#endif
35263                         }
35264 -                       
35265 -                       /* 
35266 +
35267 +                       /*
35268                          * local servers might died, but we restart them
35269 -                        * 
35270 +                        *
35271                          */
35272                         if (proc->state == PROC_STATE_DIED &&
35273                             proc->load == 0) {
35274                                 /* restart the child */
35275 -                               
35276 +
35277                                 if (p->conf.debug) {
35278                                         log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
35279                                                         "--- scgi spawning",
35280 @@ -2101,18 +1965,18 @@
35281                                                         "\n\tsocket", host->unixsocket,
35282                                                         "\n\tcurrent:", 1, "/", host->min_procs);
35283                                 }
35284 -                               
35285 +
35286                                 if (scgi_spawn_connection(srv, p, host, proc)) {
35287                                         log_error_write(srv, __FILE__, __LINE__, "s",
35288                                                         "ERROR: spawning fcgi failed.");
35289                                         return HANDLER_ERROR;
35290                                 }
35291 -                               
35292 +
35293                                 scgi_proclist_sort_down(srv, host, proc);
35294                         }
35295                 }
35296         }
35297 -       
35298 +
35299         return 0;
35300  }
35301  
35302 @@ -2121,13 +1985,13 @@
35303         plugin_data *p    = hctx->plugin_data;
35304         scgi_extension_host *host= hctx->host;
35305         connection *con   = hctx->remote_conn;
35306 -       
35307 +
35308         int ret;
35309  
35310 -       /* sanity check */      
35311 +       /* sanity check */
35312         if (!host ||
35313             ((!host->host->used || !host->port) && !host->unixsocket->used)) {
35314 -               log_error_write(srv, __FILE__, __LINE__, "sxddd", 
35315 +               log_error_write(srv, __FILE__, __LINE__, "sxddd",
35316                                 "write-req: error",
35317                                 host,
35318                                 host->host->used,
35319 @@ -2135,259 +1999,260 @@
35320                                 host->unixsocket->used);
35321                 return HANDLER_ERROR;
35322         }
35323 -       
35324 +
35325  
35326         switch(hctx->state) {
35327 -       case FCGI_STATE_INIT:
35328 +       case SCGI_STATE_INIT:
35329                 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
35330 -               
35331 -               if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
35332 +
35333 +               if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
35334                         if (errno == EMFILE ||
35335                             errno == EINTR) {
35336 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35337 -                                               "wait for fd at connection:", con->fd);
35338 -                               
35339 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
35340 +                                               "wait for fd at connection:", con->sock->fd);
35341 +
35342                                 return HANDLER_WAIT_FOR_FD;
35343                         }
35344 -                       
35345 -                       log_error_write(srv, __FILE__, __LINE__, "ssdd", 
35346 +
35347 +                       log_error_write(srv, __FILE__, __LINE__, "ssdd",
35348                                         "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
35349                         return HANDLER_ERROR;
35350                 }
35351 -               hctx->fde_ndx = -1;
35352 -               
35353 +               hctx->sock->fde_ndx = -1;
35354 +
35355                 srv->cur_fds++;
35356 -               
35357 -               fdevent_register(srv->ev, hctx->fd, scgi_handle_fdevent, hctx);
35358 -               
35359 -               if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
35360 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
35361 +
35362 +               fdevent_register(srv->ev, hctx->sock, scgi_handle_fdevent, hctx);
35363 +
35364 +               if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
35365 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
35366                                         "fcntl failed: ", strerror(errno));
35367 -                       
35368 +
35369                         return HANDLER_ERROR;
35370                 }
35371 -               
35372 +
35373                 /* fall through */
35374 -       case FCGI_STATE_CONNECT:
35375 -               if (hctx->state == FCGI_STATE_INIT) {
35376 -                       for (hctx->proc = hctx->host->first; 
35377 -                            hctx->proc && hctx->proc->state != PROC_STATE_RUNNING; 
35378 +       case SCGI_STATE_CONNECT:
35379 +               if (hctx->state == SCGI_STATE_INIT) {
35380 +                       for (hctx->proc = hctx->host->first;
35381 +                            hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
35382                              hctx->proc = hctx->proc->next);
35383 -                       
35384 +
35385                         /* all childs are dead */
35386                         if (hctx->proc == NULL) {
35387 -                               hctx->fde_ndx = -1;
35388 -                               
35389 +                               hctx->sock->fde_ndx = -1;
35390 +
35391                                 return HANDLER_ERROR;
35392                         }
35393 -                       
35394 +
35395                         if (hctx->proc->is_local) {
35396                                 hctx->pid = hctx->proc->pid;
35397                         }
35398 -                       
35399 +
35400                         switch (scgi_establish_connection(srv, hctx)) {
35401                         case 1:
35402 -                               scgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
35403 -                               
35404 +                               scgi_set_state(srv, hctx, SCGI_STATE_CONNECT);
35405 +
35406                                 /* connection is in progress, wait for an event and call getsockopt() below */
35407 -                               
35408 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35409 -                               
35410 +
35411 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35412 +
35413                                 return HANDLER_WAIT_FOR_EVENT;
35414                         case -1:
35415                                 /* if ECONNREFUSED choose another connection -> FIXME */
35416 -                               hctx->fde_ndx = -1;
35417 -                               
35418 +                               hctx->sock->fde_ndx = -1;
35419 +
35420                                 return HANDLER_ERROR;
35421                         default:
35422                                 /* everything is ok, go on */
35423                                 break;
35424                         }
35425  
35426 -                       
35427 +
35428                 } else {
35429                         int socket_error;
35430                         socklen_t socket_error_len = sizeof(socket_error);
35431 -                       
35432 +
35433                         /* try to finish the connect() */
35434 -                       if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
35435 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
35436 +                       if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
35437 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
35438                                                 "getsockopt failed:", strerror(errno));
35439 -                               
35440 +
35441                                 return HANDLER_ERROR;
35442                         }
35443                         if (socket_error != 0) {
35444                                 if (!hctx->proc->is_local || p->conf.debug) {
35445                                         /* local procs get restarted */
35446 -                                       
35447 +
35448                                         log_error_write(srv, __FILE__, __LINE__, "ss",
35449 -                                                       "establishing connection failed:", strerror(socket_error), 
35450 +                                                       "establishing connection failed:", strerror(socket_error),
35451                                                         "port:", hctx->proc->port);
35452                                 }
35453 -                               
35454 +
35455                                 return HANDLER_ERROR;
35456                         }
35457                 }
35458 -               
35459 +
35460                 /* ok, we have the connection */
35461 -               
35462 +
35463                 hctx->proc->load++;
35464                 hctx->proc->last_used = srv->cur_ts;
35465                 hctx->got_proc = 1;
35466 -               
35467 +
35468                 if (p->conf.debug) {
35469                         log_error_write(srv, __FILE__, __LINE__, "sddbdd",
35470 -                                       "got proc:", 
35471 -                                       hctx->fd,
35472 -                                       hctx->proc->pid, 
35473 -                                       hctx->proc->socket, 
35474 +                                       "got proc:",
35475 +                                       hctx->sock->fd,
35476 +                                       hctx->proc->pid,
35477 +                                       hctx->proc->socket,
35478                                         hctx->proc->port,
35479                                         hctx->proc->load);
35480                 }
35481  
35482                 /* move the proc-list entry down the list */
35483                 scgi_proclist_sort_up(srv, hctx->host, hctx->proc);
35484 -               
35485 -               scgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
35486 +
35487 +               scgi_set_state(srv, hctx, SCGI_STATE_PREPARE_WRITE);
35488                 /* fall through */
35489 -       case FCGI_STATE_PREPARE_WRITE:
35490 +       case SCGI_STATE_PREPARE_WRITE:
35491                 scgi_create_env(srv, hctx);
35492 -               
35493 -               scgi_set_state(srv, hctx, FCGI_STATE_WRITE);
35494 -               
35495 +
35496 +               scgi_set_state(srv, hctx, SCGI_STATE_WRITE);
35497 +
35498                 /* fall through */
35499 -       case FCGI_STATE_WRITE:
35500 -               ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); 
35501 +       case SCGI_STATE_WRITE:
35502 +               ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
35503  
35504                 chunkqueue_remove_finished_chunks(hctx->wb);
35505 -       
35506 +
35507                 if (-1 == ret) {
35508                         if (errno == ENOTCONN) {
35509 -                               /* the connection got dropped after accept() 
35510 -                                * 
35511 -                                * this is most of the time a PHP which dies 
35512 +                               /* the connection got dropped after accept()
35513 +                                *
35514 +                                * this is most of the time a PHP which dies
35515                                  * after PHP_FCGI_MAX_REQUESTS
35516 -                                * 
35517 -                                */ 
35518 +                                *
35519 +                                */
35520                                 if (hctx->wb->bytes_out == 0 &&
35521                                     hctx->reconnects < 5) {
35522 -                                       usleep(10000); /* take away the load of the webserver 
35523 -                                                       * to let the php a chance to restart 
35524 +#ifndef _WIN32
35525 +                                       usleep(10000); /* take away the load of the webserver
35526 +                                                       * to let the php a chance to restart
35527                                                         */
35528 -                                       
35529 +#endif
35530                                         scgi_reconnect(srv, hctx);
35531 -                               
35532 +
35533                                         return HANDLER_WAIT_FOR_FD;
35534                                 }
35535 -                               
35536 +
35537                                 /* not reconnected ... why
35538 -                                * 
35539 +                                *
35540                                  * far@#lighttpd report this for FreeBSD
35541 -                                * 
35542 +                                *
35543                                  */
35544 -                               
35545 -                               log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
35546 +
35547 +                               log_error_write(srv, __FILE__, __LINE__, "ssosd",
35548                                                 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
35549                                                 "write-offset:", hctx->wb->bytes_out,
35550                                                 "reconnect attempts:", hctx->reconnects);
35551 -                               
35552 +
35553                                 return HANDLER_ERROR;
35554                         }
35555 -                       
35556 +
35557                         if ((errno != EAGAIN) &&
35558                             (errno != EINTR)) {
35559 -                               
35560 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", 
35561 +
35562 +                               log_error_write(srv, __FILE__, __LINE__, "ssd",
35563                                                 "write failed:", strerror(errno), errno);
35564 -                               
35565 +
35566                                 return HANDLER_ERROR;
35567                         } else {
35568 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35569 -                               
35570 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35571 +
35572                                 return HANDLER_WAIT_FOR_EVENT;
35573                         }
35574                 }
35575 -               
35576 +
35577                 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
35578                         /* we don't need the out event anymore */
35579 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
35580 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
35581 -                       scgi_set_state(srv, hctx, FCGI_STATE_READ);
35582 +                       fdevent_event_del(srv->ev, hctx->sock);
35583 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
35584 +                       scgi_set_state(srv, hctx, SCGI_STATE_RESPONSE_HEADER);
35585                 } else {
35586 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35587 -                       
35588 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35589 +
35590                         return HANDLER_WAIT_FOR_EVENT;
35591                 }
35592 -               
35593 +
35594                 break;
35595 -       case FCGI_STATE_READ:
35596 +       case SCGI_STATE_RESPONSE_HEADER:
35597                 /* waiting for a response */
35598                 break;
35599         default:
35600                 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
35601                 return HANDLER_ERROR;
35602         }
35603 -       
35604 +
35605         return HANDLER_WAIT_FOR_EVENT;
35606  }
35607  
35608  SUBREQUEST_FUNC(mod_scgi_handle_subrequest) {
35609         plugin_data *p = p_d;
35610 -       
35611 +
35612         handler_ctx *hctx = con->plugin_ctx[p->id];
35613         scgi_proc *proc;
35614         scgi_extension_host *host;
35615 -       
35616 +
35617         if (NULL == hctx) return HANDLER_GO_ON;
35618 -       
35619 +
35620         /* not my job */
35621         if (con->mode != p->id) return HANDLER_GO_ON;
35622 -       
35623 +
35624         /* ok, create the request */
35625         switch(scgi_write_request(srv, hctx)) {
35626         case HANDLER_ERROR:
35627                 proc = hctx->proc;
35628                 host = hctx->host;
35629 -               
35630 -               if (proc && 
35631 +
35632 +               if (proc &&
35633                     0 == proc->is_local &&
35634                     proc->state != PROC_STATE_DISABLED) {
35635                         /* only disable remote servers as we don't manage them*/
35636 -                       
35637 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "fcgi-server disabled:", 
35638 +
35639 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "fcgi-server disabled:",
35640                                         host->host,
35641                                         proc->port,
35642                                         proc->socket);
35643 -                       
35644 +
35645                         /* disable this server */
35646                         proc->disable_ts = srv->cur_ts;
35647                         proc->state = PROC_STATE_DISABLED;
35648                         host->active_procs--;
35649                 }
35650 -               
35651 -               if (hctx->state == FCGI_STATE_INIT ||
35652 -                   hctx->state == FCGI_STATE_CONNECT) {
35653 -                       /* connect() or getsockopt() failed, 
35654 -                        * restart the request-handling 
35655 +
35656 +               if (hctx->state == SCGI_STATE_INIT ||
35657 +                   hctx->state == SCGI_STATE_CONNECT) {
35658 +                       /* connect() or getsockopt() failed,
35659 +                        * restart the request-handling
35660                          */
35661                         if (proc && proc->is_local) {
35662  
35663                                 if (p->conf.debug) {
35664 -                                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "connect() to scgi failed, restarting the request-handling:", 
35665 +                                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "connect() to scgi failed, restarting the request-handling:",
35666                                                         host->host,
35667                                                         proc->port,
35668                                                         proc->socket);
35669                                 }
35670  
35671 -                               /* 
35672 +                               /*
35673                                  * several hctx might reference the same proc
35674 -                                * 
35675 +                                *
35676                                  * Only one of them should mark the proc as dead all the other
35677                                  * ones should just take a new one.
35678 -                                * 
35679 +                                *
35680                                  * If a new proc was started with the old struct this might lead
35681                                  * the mark a perfect proc as dead otherwise
35682 -                                * 
35683 +                                *
35684                                  */
35685                                 if (proc->state == PROC_STATE_RUNNING &&
35686                                     hctx->pid == proc->pid) {
35687 @@ -2395,25 +2260,25 @@
35688                                 }
35689                         }
35690                         scgi_restart_dead_procs(srv, p, host);
35691 -                       
35692 +
35693                         scgi_connection_cleanup(srv, hctx);
35694 -                       
35695 +
35696                         buffer_reset(con->physical.path);
35697                         con->mode = DIRECT;
35698                         joblist_append(srv, con);
35699 -                       
35700 -                       /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop 
35701 -                        * and hope that the childs will be restarted 
35702 -                        * 
35703 +
35704 +                       /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
35705 +                        * and hope that the childs will be restarted
35706 +                        *
35707                          */
35708                         return HANDLER_WAIT_FOR_FD;
35709                 } else {
35710                         scgi_connection_cleanup(srv, hctx);
35711 -                       
35712 +
35713                         buffer_reset(con->physical.path);
35714                         con->mode = DIRECT;
35715                         con->http_status = 503;
35716 -                       
35717 +
35718                         return HANDLER_FINISHED;
35719                 }
35720         case HANDLER_WAIT_FOR_EVENT:
35721 @@ -2433,23 +2298,23 @@
35722  static handler_t scgi_connection_close(server *srv, handler_ctx *hctx) {
35723         plugin_data *p;
35724         connection  *con;
35725 -       
35726 +
35727         if (NULL == hctx) return HANDLER_GO_ON;
35728 -       
35729 +
35730         p    = hctx->plugin_data;
35731         con  = hctx->remote_conn;
35732 -       
35733 +
35734         if (con->mode != p->id) return HANDLER_GO_ON;
35735 -       
35736 -       log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
35737 -                       "emergency exit: scgi:", 
35738 -                       "connection-fd:", con->fd,
35739 -                       "fcgi-fd:", hctx->fd);
35740 -       
35741 -       
35742 -       
35743 +
35744 +       log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35745 +                       "emergency exit: scgi:",
35746 +                       "connection-fd:", con->sock->fd,
35747 +                       "fcgi-fd:", hctx->sock->fd);
35748 +
35749 +
35750 +
35751         scgi_connection_cleanup(srv, hctx);
35752 -       
35753 +
35754         return HANDLER_FINISHED;
35755  }
35756  
35757 @@ -2459,27 +2324,28 @@
35758         handler_ctx *hctx = ctx;
35759         connection  *con  = hctx->remote_conn;
35760         plugin_data *p    = hctx->plugin_data;
35761 -       
35762 +
35763         scgi_proc *proc   = hctx->proc;
35764         scgi_extension_host *host= hctx->host;
35765  
35766         if ((revents & FDEVENT_IN) &&
35767 -           hctx->state == FCGI_STATE_READ) {
35768 +           (hctx->state == SCGI_STATE_RESPONSE_HEADER ||
35769 +            hctx->state == SCGI_STATE_RESPONSE_CONTENT)) {
35770                 switch (scgi_demux_response(srv, hctx)) {
35771                 case 0:
35772                         break;
35773                 case 1:
35774                         /* we are done */
35775                         scgi_connection_cleanup(srv, hctx);
35776 -                       
35777 +
35778                         joblist_append(srv, con);
35779                         return HANDLER_FINISHED;
35780                 case -1:
35781                         if (proc->pid && proc->state != PROC_STATE_DIED) {
35782                                 int status;
35783 -                               
35784 +
35785                                 /* only fetch the zombie if it is not already done */
35786 -                               
35787 +#ifndef _WIN32
35788                                 switch(waitpid(proc->pid, &status, WNOHANG)) {
35789                                 case 0:
35790                                         /* child is still alive */
35791 @@ -2489,19 +2355,19 @@
35792                                 default:
35793                                         /* the child should not terminate at all */
35794                                         if (WIFEXITED(status)) {
35795 -                                               log_error_write(srv, __FILE__, __LINE__, "sdsd", 
35796 +                                               log_error_write(srv, __FILE__, __LINE__, "sdsd",
35797                                                                 "child exited, pid:", proc->pid,
35798                                                                 "status:", WEXITSTATUS(status));
35799                                         } else if (WIFSIGNALED(status)) {
35800 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35801 -                                                               "child signaled:", 
35802 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
35803 +                                                               "child signaled:",
35804                                                                 WTERMSIG(status));
35805                                         } else {
35806 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35807 -                                                               "child died somehow:", 
35808 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
35809 +                                                               "child died somehow:",
35810                                                                 status);
35811                                         }
35812 -                                       
35813 +
35814                                         if (p->conf.debug) {
35815                                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
35816                                                                 "--- scgi spawning",
35817 @@ -2509,40 +2375,41 @@
35818                                                                 "\n\tsocket", host->unixsocket,
35819                                                                 "\n\tcurrent:", 1, "/", host->min_procs);
35820                                         }
35821 -                                       
35822 +
35823                                         if (scgi_spawn_connection(srv, p, host, proc)) {
35824                                                 /* child died */
35825                                                 proc->state = PROC_STATE_DIED;
35826                                         } else {
35827                                                 scgi_proclist_sort_down(srv, host, proc);
35828                                         }
35829 -                                       
35830 +
35831                                         break;
35832                                 }
35833 +#endif
35834                         }
35835  
35836                         if (con->file_started == 0) {
35837                                 /* nothing has been send out yet, try to use another child */
35838 -                               
35839 +
35840                                 if (hctx->wb->bytes_out == 0 &&
35841                                     hctx->reconnects < 5) {
35842                                         scgi_reconnect(srv, hctx);
35843 -                                       
35844 -                                       log_error_write(srv, __FILE__, __LINE__, "sdsdsd", 
35845 +
35846 +                                       log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
35847                                                 "response not sent, request not sent, reconnection.",
35848 -                                               "connection-fd:", con->fd,
35849 -                                               "fcgi-fd:", hctx->fd);
35850 -                                       
35851 +                                               "connection-fd:", con->sock->fd,
35852 +                                               "fcgi-fd:", hctx->sock->fd);
35853 +
35854                                         return HANDLER_WAIT_FOR_FD;
35855                                 }
35856 -                               
35857 -                               log_error_write(srv, __FILE__, __LINE__, "sdsdsd", 
35858 +
35859 +                               log_error_write(srv, __FILE__, __LINE__, "sosdsd",
35860                                                 "response not sent, request sent:", hctx->wb->bytes_out,
35861 -                                               "connection-fd:", con->fd,
35862 -                                               "fcgi-fd:", hctx->fd);
35863 -                               
35864 +                                               "connection-fd:", con->sock->fd,
35865 +                                               "fcgi-fd:", hctx->sock->fd);
35866 +
35867                                 scgi_connection_cleanup(srv, hctx);
35868 -                               
35869 +
35870                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
35871                                 buffer_reset(con->physical.path);
35872                                 con->http_status = 500;
35873 @@ -2550,76 +2417,77 @@
35874                         } else {
35875                                 /* response might have been already started, kill the connection */
35876                                 scgi_connection_cleanup(srv, hctx);
35877 -                               
35878 -                               log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
35879 +
35880 +                               log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35881                                                 "response already sent out, termination connection",
35882 -                                               "connection-fd:", con->fd,
35883 -                                               "fcgi-fd:", hctx->fd);
35884 -                               
35885 +                                               "connection-fd:", con->sock->fd,
35886 +                                               "fcgi-fd:", hctx->sock->fd);
35887 +
35888                                 connection_set_state(srv, con, CON_STATE_ERROR);
35889                         }
35890  
35891                         /* */
35892 -                       
35893 -                       
35894 +
35895 +
35896                         joblist_append(srv, con);
35897                         return HANDLER_FINISHED;
35898                 }
35899         }
35900 -       
35901 +
35902         if (revents & FDEVENT_OUT) {
35903 -               if (hctx->state == FCGI_STATE_CONNECT ||
35904 -                   hctx->state == FCGI_STATE_WRITE) {
35905 +               if (hctx->state == SCGI_STATE_CONNECT ||
35906 +                   hctx->state == SCGI_STATE_WRITE) {
35907                         /* we are allowed to send something out
35908 -                        * 
35909 +                        *
35910                          * 1. in a unfinished connect() call
35911                          * 2. in a unfinished write() call (long POST request)
35912                          */
35913                         return mod_scgi_handle_subrequest(srv, con, p);
35914                 } else {
35915 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
35916 -                                       "got a FDEVENT_OUT and didn't know why:", 
35917 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
35918 +                                       "got a FDEVENT_OUT and didn't know why:",
35919                                         hctx->state);
35920                 }
35921         }
35922 -       
35923 +
35924         /* perhaps this issue is already handled */
35925         if (revents & FDEVENT_HUP) {
35926 -               if (hctx->state == FCGI_STATE_CONNECT) {
35927 +               if (hctx->state == SCGI_STATE_CONNECT) {
35928                         /* getoptsock will catch this one (right ?)
35929 -                        * 
35930 -                        * if we are in connect we might get a EINPROGRESS 
35931 -                        * in the first call and a FDEVENT_HUP in the 
35932 +                        *
35933 +                        * if we are in connect we might get a EINPROGRESS
35934 +                        * in the first call and a FDEVENT_HUP in the
35935                          * second round
35936 -                        * 
35937 +                        *
35938                          * FIXME: as it is a bit ugly.
35939 -                        * 
35940 +                        *
35941                          */
35942                         return mod_scgi_handle_subrequest(srv, con, p);
35943 -               } else if (hctx->state == FCGI_STATE_READ &&
35944 +               } else if ((hctx->state == SCGI_STATE_RESPONSE_HEADER ||
35945 +                           hctx->state == SCGI_STATE_RESPONSE_CONTENT ) &&
35946                            hctx->proc->port == 0) {
35947                         /* FIXME:
35948 -                        * 
35949 +                        *
35950                          * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
35951                          * even if the FCGI_FIN packet is not received yet
35952                          */
35953                 } else {
35954 -                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd", 
35955 -                                       "error: unexpected close of scgi connection for", 
35956 +                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
35957 +                                       "error: unexpected close of scgi connection for",
35958                                         con->uri.path,
35959 -                                       "(no scgi process on host: ", 
35960 +                                       "(no scgi process on host: ",
35961                                         host->host,
35962 -                                       ", port: ", 
35963 +                                       ", port: ",
35964                                         host->port,
35965                                         " ?)",
35966                                         hctx->state);
35967 -                       
35968 +
35969                         connection_set_state(srv, con, CON_STATE_ERROR);
35970                         scgi_connection_close(srv, hctx);
35971                         joblist_append(srv, con);
35972                 }
35973         } else if (revents & FDEVENT_ERR) {
35974 -               log_error_write(srv, __FILE__, __LINE__, "s", 
35975 +               log_error_write(srv, __FILE__, __LINE__, "s",
35976                                 "fcgi: got a FDEVENT_ERR. Don't know why.");
35977                 /* kill all connections to the scgi process */
35978  
35979 @@ -2628,42 +2496,39 @@
35980                 scgi_connection_close(srv, hctx);
35981                 joblist_append(srv, con);
35982         }
35983 -       
35984 +
35985         return HANDLER_FINISHED;
35986  }
35987 -#define PATCH(x) \
35988 -       p->conf.x = s->x;
35989 +
35990  static int scgi_patch_connection(server *srv, connection *con, plugin_data *p) {
35991         size_t i, j;
35992         plugin_config *s = p->config_storage[0];
35993 -       
35994 -       PATCH(exts);
35995 -       PATCH(debug);
35996 -       
35997 +
35998 +       PATCH_OPTION(exts);
35999 +       PATCH_OPTION(debug);
36000 +
36001         /* skip the first, the global context */
36002         for (i = 1; i < srv->config_context->used; i++) {
36003                 data_config *dc = (data_config *)srv->config_context->data[i];
36004                 s = p->config_storage[i];
36005 -               
36006 +
36007                 /* condition didn't match */
36008                 if (!config_check_cond(srv, con, dc)) continue;
36009 -               
36010 +
36011                 /* merge config */
36012                 for (j = 0; j < dc->value->used; j++) {
36013                         data_unset *du = dc->value->data[j];
36014 -                       
36015 +
36016                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.server"))) {
36017 -                               PATCH(exts);
36018 +                               PATCH_OPTION(exts);
36019                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.debug"))) {
36020 -                               PATCH(debug);
36021 +                               PATCH_OPTION(debug);
36022                         }
36023                 }
36024         }
36025 -       
36026 +
36027         return 0;
36028  }
36029 -#undef PATCH
36030 -
36031  
36032  static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
36033         plugin_data *p = p_d;
36034 @@ -2673,30 +2538,30 @@
36035         size_t k;
36036         buffer *fn;
36037         scgi_extension *extension = NULL;
36038 -       
36039 +
36040         /* Possibly, we processed already this request */
36041         if (con->file_started == 1) return HANDLER_GO_ON;
36042 -       
36043 +
36044         fn = uri_path_handler ? con->uri.path : con->physical.path;
36045  
36046         if (buffer_is_empty(fn)) return HANDLER_GO_ON;
36047  
36048         s_len = fn->used - 1;
36049 -       
36050 +
36051         scgi_patch_connection(srv, con, p);
36052  
36053         /* check if extension matches */
36054         for (k = 0; k < p->conf.exts->used; k++) {
36055                 size_t ct_len;
36056 -               
36057 +
36058                 extension = p->conf.exts->exts[k];
36059 -               
36060 +
36061                 if (extension->key->used == 0) continue;
36062 -               
36063 +
36064                 ct_len = extension->key->used - 1;
36065 -               
36066 +
36067                 if (s_len < ct_len) continue;
36068 -               
36069 +
36070                 /* check extension in the form "/scgi_pattern" */
36071                 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
36072                         break;
36073 @@ -2710,17 +2575,17 @@
36074         if (k == p->conf.exts->used) {
36075                 return HANDLER_GO_ON;
36076         }
36077 -       
36078 +
36079         /* get best server */
36080         for (k = 0, ndx = -1; k < extension->used; k++) {
36081                 scgi_extension_host *host = extension->hosts[k];
36082 -               
36083 +
36084                 /* we should have at least one proc that can do somthing */
36085                 if (host->active_procs == 0) continue;
36086  
36087                 if (used == -1 || host->load < used) {
36088                         used = host->load;
36089 -                       
36090 +
36091                         ndx = k;
36092                 }
36093         }
36094 @@ -2728,12 +2593,12 @@
36095         /* found a server */
36096         if (ndx != -1) {
36097                 scgi_extension_host *host = extension->hosts[ndx];
36098 -               
36099 -               /* 
36100 -                * if check-local is disabled, use the uri.path handler 
36101 -                * 
36102 +
36103 +               /*
36104 +                * if check-local is disabled, use the uri.path handler
36105 +                *
36106                  */
36107 -               
36108 +
36109                 /* init handler-context */
36110                 if (uri_path_handler) {
36111                         if (host->check_local == 0) {
36112 @@ -2741,7 +2606,7 @@
36113                                 char *pathinfo;
36114  
36115                                 hctx = handler_ctx_init();
36116 -                               
36117 +
36118                                 hctx->remote_conn      = con;
36119                                 hctx->plugin_data      = p;
36120                                 hctx->host             = host;
36121 @@ -2749,45 +2614,45 @@
36122  
36123                                 hctx->conf.exts        = p->conf.exts;
36124                                 hctx->conf.debug       = p->conf.debug;
36125 -                               
36126 +
36127                                 con->plugin_ctx[p->id] = hctx;
36128 -                               
36129 +
36130                                 host->load++;
36131 -                               
36132 +
36133                                 con->mode = p->id;
36134  
36135                                 if (con->conf.log_request_handling) {
36136                                         log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_scgi");
36137                                 }
36138  
36139 -                               /* the prefix is the SCRIPT_NAME, 
36140 +                               /* the prefix is the SCRIPT_NAME,
36141                                  * everthing from start to the next slash
36142                                  * this is important for check-local = "disable"
36143 -                                * 
36144 +                                *
36145                                  * if prefix = /admin.fcgi
36146 -                                * 
36147 +                                *
36148                                  * /admin.fcgi/foo/bar
36149 -                                * 
36150 +                                *
36151                                  * SCRIPT_NAME = /admin.fcgi
36152                                  * PATH_INFO   = /foo/bar
36153 -                                * 
36154 +                                *
36155                                  * if prefix = /fcgi-bin/
36156 -                                * 
36157 +                                *
36158                                  * /fcgi-bin/foo/bar
36159 -                                * 
36160 +                                *
36161                                  * SCRIPT_NAME = /fcgi-bin/foo
36162                                  * PATH_INFO   = /bar
36163 -                                * 
36164 +                                *
36165                                  */
36166 -                               
36167 +
36168                                 /* the rewrite is only done for /prefix/? matches */
36169                                 if (extension->key->ptr[0] == '/' &&
36170                                     con->uri.path->used > extension->key->used &&
36171                                     NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
36172 -                                       /* rewrite uri.path and pathinfo */ 
36173 -                                       
36174 +                                       /* rewrite uri.path and pathinfo */
36175 +
36176                                         buffer_copy_string(con->request.pathinfo, pathinfo);
36177 -                                       
36178 +
36179                                         con->uri.path->used -= con->request.pathinfo->used - 1;
36180                                         con->uri.path->ptr[con->uri.path->used - 1] = '\0';
36181                                 }
36182 @@ -2796,21 +2661,21 @@
36183                 } else {
36184                         handler_ctx *hctx;
36185                         hctx = handler_ctx_init();
36186 -                       
36187 +
36188                         hctx->remote_conn      = con;
36189                         hctx->plugin_data      = p;
36190                         hctx->host             = host;
36191                         hctx->proc             = NULL;
36192 -                       
36193 +
36194                         hctx->conf.exts        = p->conf.exts;
36195                         hctx->conf.debug       = p->conf.debug;
36196 -                       
36197 +
36198                         con->plugin_ctx[p->id] = hctx;
36199 -                       
36200 +
36201                         host->load++;
36202 -                       
36203 +
36204                         con->mode = p->id;
36205 -                       
36206 +
36207                         if (con->conf.log_request_handling) {
36208                                 log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
36209                         }
36210 @@ -2821,11 +2686,11 @@
36211                 /* no handler found */
36212                 buffer_reset(con->physical.path);
36213                 con->http_status = 500;
36214 -               
36215 -               log_error_write(srv, __FILE__, __LINE__,  "sb", 
36216 -                               "no fcgi-handler found for:", 
36217 +
36218 +               log_error_write(srv, __FILE__, __LINE__,  "sb",
36219 +                               "no fcgi-handler found for:",
36220                                 fn);
36221 -               
36222 +
36223                 return HANDLER_FINISHED;
36224         }
36225         return HANDLER_GO_ON;
36226 @@ -2844,21 +2709,22 @@
36227  JOBLIST_FUNC(mod_scgi_handle_joblist) {
36228         plugin_data *p = p_d;
36229         handler_ctx *hctx = con->plugin_ctx[p->id];
36230 -       
36231 +
36232         if (hctx == NULL) return HANDLER_GO_ON;
36233  
36234 -       if (hctx->fd != -1) {
36235 +       if (hctx->sock->fd != -1) {
36236                 switch (hctx->state) {
36237 -               case FCGI_STATE_READ:
36238 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
36239 -                       
36240 +               case SCGI_STATE_RESPONSE_HEADER:
36241 +               case SCGI_STATE_RESPONSE_CONTENT:
36242 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
36243 +
36244                         break;
36245 -               case FCGI_STATE_CONNECT:
36246 -               case FCGI_STATE_WRITE:
36247 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
36248 -                       
36249 +               case SCGI_STATE_CONNECT:
36250 +               case SCGI_STATE_WRITE:
36251 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
36252 +
36253                         break;
36254 -               case FCGI_STATE_INIT:
36255 +               case SCGI_STATE_INIT:
36256                         /* at reconnect */
36257                         break;
36258                 default:
36259 @@ -2873,21 +2739,21 @@
36260  
36261  static handler_t scgi_connection_close_callback(server *srv, connection *con, void *p_d) {
36262         plugin_data *p = p_d;
36263 -       
36264 +
36265         return scgi_connection_close(srv, con->plugin_ctx[p->id]);
36266  }
36267  
36268  TRIGGER_FUNC(mod_scgi_handle_trigger) {
36269         plugin_data *p = p_d;
36270         size_t i, j, n;
36271 -       
36272 -       
36273 +
36274 +
36275         /* perhaps we should kill a connect attempt after 10-15 seconds
36276 -        * 
36277 +        *
36278          * currently we wait for the TCP timeout which is on Linux 180 seconds
36279 -        * 
36280 -        * 
36281 -        * 
36282 +        *
36283 +        *
36284 +        *
36285          */
36286  
36287         /* check all childs if they are still up */
36288 @@ -2904,47 +2770,47 @@
36289                         scgi_extension *ex;
36290  
36291                         ex = exts->exts[j];
36292 -                       
36293 +
36294                         for (n = 0; n < ex->used; n++) {
36295 -                               
36296 +
36297                                 scgi_proc *proc;
36298                                 unsigned long sum_load = 0;
36299                                 scgi_extension_host *host;
36300 -                               
36301 +
36302                                 host = ex->hosts[n];
36303 -                               
36304 +
36305                                 scgi_restart_dead_procs(srv, p, host);
36306 -                               
36307 +
36308                                 for (proc = host->first; proc; proc = proc->next) {
36309                                         sum_load += proc->load;
36310                                 }
36311 -                               
36312 +
36313                                 if (host->num_procs &&
36314                                     host->num_procs < host->max_procs &&
36315                                     (sum_load / host->num_procs) > host->max_load_per_proc) {
36316                                         /* overload, spawn new child */
36317                                         scgi_proc *fp = NULL;
36318 -                                       
36319 +
36320                                         if (p->conf.debug) {
36321 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
36322 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
36323                                                                 "overload detected, spawning a new child");
36324                                         }
36325 -                                       
36326 +
36327                                         for (fp = host->unused_procs; fp && fp->pid != 0; fp = fp->next);
36328 -                                       
36329 +
36330                                         if (fp) {
36331                                                 if (fp == host->unused_procs) host->unused_procs = fp->next;
36332 -                                               
36333 +
36334                                                 if (fp->next) fp->next->prev = NULL;
36335 -                                               
36336 +
36337                                                 host->max_id++;
36338                                         } else {
36339                                                 fp = scgi_process_init();
36340                                                 fp->id = host->max_id++;
36341                                         }
36342 -                                       
36343 +
36344                                         host->num_procs++;
36345 -                                       
36346 +
36347                                         if (buffer_is_empty(host->unixsocket)) {
36348                                                 fp->port = host->port + fp->id;
36349                                         } else {
36350 @@ -2952,13 +2818,13 @@
36351                                                 buffer_append_string(fp->socket, "-");
36352                                                 buffer_append_long(fp->socket, fp->id);
36353                                         }
36354 -                                       
36355 +
36356                                         if (scgi_spawn_connection(srv, p, host, fp)) {
36357                                                 log_error_write(srv, __FILE__, __LINE__, "s",
36358                                                                 "ERROR: spawning fcgi failed.");
36359                                                 return HANDLER_ERROR;
36360                                         }
36361 -                                       
36362 +
36363                                         fp->prev = NULL;
36364                                         fp->next = host->first;
36365                                         if (host->first) {
36366 @@ -2966,56 +2832,57 @@
36367                                         }
36368                                         host->first = fp;
36369                                 }
36370 -                               
36371 +
36372                                 for (proc = host->first; proc; proc = proc->next) {
36373                                         if (proc->load != 0) break;
36374                                         if (host->num_procs <= host->min_procs) break;
36375                                         if (proc->pid == 0) continue;
36376 -                                       
36377 +#ifndef _WIN32
36378                                         if (srv->cur_ts - proc->last_used > host->idle_timeout) {
36379                                                 /* a proc is idling for a long time now,
36380                                                  * terminated it */
36381 -                                               
36382 +
36383                                                 if (p->conf.debug) {
36384 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
36385 -                                                                       "idle-timeout reached, terminating child:", 
36386 -                                                                       "socket:", proc->socket, 
36387 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd",
36388 +                                                                       "idle-timeout reached, terminating child:",
36389 +                                                                       "socket:", proc->socket,
36390                                                                         "pid", proc->pid);
36391                                                 }
36392 -                                               
36393 -                                               
36394 +
36395 +
36396                                                 if (proc->next) proc->next->prev = proc->prev;
36397                                                 if (proc->prev) proc->prev->next = proc->next;
36398 -                                               
36399 +
36400                                                 if (proc->prev == NULL) host->first = proc->next;
36401 -                                               
36402 +
36403                                                 proc->prev = NULL;
36404                                                 proc->next = host->unused_procs;
36405 -                                               
36406 +
36407                                                 if (host->unused_procs) host->unused_procs->prev = proc;
36408                                                 host->unused_procs = proc;
36409 -                                               
36410 +
36411                                                 kill(proc->pid, SIGTERM);
36412 -                                               
36413 +
36414                                                 proc->state = PROC_STATE_KILLED;
36415 -                                               
36416 -                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
36417 -                                                                       "killed:", 
36418 -                                                                       "socket:", proc->socket, 
36419 +
36420 +                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd",
36421 +                                                                       "killed:",
36422 +                                                                       "socket:", proc->socket,
36423                                                                         "pid", proc->pid);
36424 -                                               
36425 +
36426                                                 host->num_procs--;
36427 -                                               
36428 +
36429                                                 /* proc is now in unused, let the next second handle the next process */
36430                                                 break;
36431 -                                       }       
36432 +                                       }
36433 +#endif
36434                                 }
36435 -                               
36436 +
36437                                 for (proc = host->unused_procs; proc; proc = proc->next) {
36438                                         int status;
36439 -                                       
36440 +
36441                                         if (proc->pid == 0) continue;
36442 -                                       
36443 +#ifndef _WIN32
36444                                         switch (waitpid(proc->pid, &status, WNOHANG)) {
36445                                         case 0:
36446                                                 /* child still running after timeout, good */
36447 @@ -3023,10 +2890,10 @@
36448                                         case -1:
36449                                                 if (errno != EINTR) {
36450                                                         /* no PID found ? should never happen */
36451 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddss", 
36452 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddss",
36453                                                                         "pid ", proc->pid, proc->state,
36454                                                                         "not found:", strerror(errno));
36455 -                                                       
36456 +
36457  #if 0
36458                                                         if (errno == ECHILD) {
36459                                                                 /* someone else has cleaned up for us */
36460 @@ -3040,25 +2907,26 @@
36461                                                 /* the child should not terminate at all */
36462                                                 if (WIFEXITED(status)) {
36463                                                         if (proc->state != PROC_STATE_KILLED) {
36464 -                                                               log_error_write(srv, __FILE__, __LINE__, "sdb", 
36465 -                                                                               "child exited:", 
36466 +                                                               log_error_write(srv, __FILE__, __LINE__, "sdb",
36467 +                                                                               "child exited:",
36468                                                                                 WEXITSTATUS(status), proc->socket);
36469                                                         }
36470                                                 } else if (WIFSIGNALED(status)) {
36471                                                         if (WTERMSIG(status) != SIGTERM) {
36472 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
36473 -                                                                               "child signaled:", 
36474 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
36475 +                                                                               "child signaled:",
36476                                                                                 WTERMSIG(status));
36477                                                         }
36478                                                 } else {
36479 -                                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
36480 -                                                                       "child died somehow:", 
36481 +                                                       log_error_write(srv, __FILE__, __LINE__, "sd",
36482 +                                                                       "child died somehow:",
36483                                                                         status);
36484                                                 }
36485                                                 proc->pid = 0;
36486                                                 proc->state = PROC_STATE_UNSET;
36487                                                 host->max_id--;
36488                                         }
36489 +#endif
36490                                 }
36491                         }
36492                 }
36493 @@ -3082,8 +2950,8 @@
36494         p->handle_subrequest       = mod_scgi_handle_subrequest;
36495         p->handle_joblist          = mod_scgi_handle_joblist;
36496         p->handle_trigger          = mod_scgi_handle_trigger;
36497 -       
36498 +
36499         p->data         = NULL;
36500 -       
36501 +
36502         return 0;
36503  }
36504 --- ../lighttpd-1.4.11/src/mod_secure_download.c        2005-12-14 14:37:29.000000000 +0200
36505 +++ lighttpd-1.4.12/src/mod_secure_download.c   2006-07-16 00:26:03.000000000 +0300
36506 @@ -25,7 +25,7 @@
36507  #ifdef USE_OPENSSL
36508  #define IN const
36509  #else
36510 -#define IN 
36511 +#define IN
36512  #endif
36513  #define OUT
36514  
36515 @@ -36,28 +36,28 @@
36516         buffer *doc_root;
36517         buffer *secret;
36518         buffer *uri_prefix;
36519 -       
36520 +
36521         unsigned short timeout;
36522  } plugin_config;
36523  
36524  typedef struct {
36525         PLUGIN_DATA;
36526 -       
36527 +
36528         buffer *md5;
36529 -       
36530 +
36531         plugin_config **config_storage;
36532 -       
36533 -       plugin_config conf; 
36534 +
36535 +       plugin_config conf;
36536  } plugin_data;
36537  
36538  /* init the plugin data */
36539  INIT_FUNC(mod_secdownload_init) {
36540         plugin_data *p;
36541 -       
36542 +
36543         p = calloc(1, sizeof(*p));
36544 -       
36545 +
36546         p->md5 = buffer_init();
36547 -       
36548 +
36549         return p;
36550  }
36551  
36552 @@ -65,27 +65,27 @@
36553  FREE_FUNC(mod_secdownload_free) {
36554         plugin_data *p = p_d;
36555         UNUSED(srv);
36556 -       
36557 +
36558         if (!p) return HANDLER_GO_ON;
36559 -       
36560 +
36561         if (p->config_storage) {
36562                 size_t i;
36563                 for (i = 0; i < srv->config_context->used; i++) {
36564                         plugin_config *s = p->config_storage[i];
36565 -                       
36566 +
36567                         buffer_free(s->secret);
36568                         buffer_free(s->doc_root);
36569                         buffer_free(s->uri_prefix);
36570 -                       
36571 +
36572                         free(s);
36573                 }
36574                 free(p->config_storage);
36575         }
36576 -       
36577 +
36578         buffer_free(p->md5);
36579 -       
36580 +
36581         free(p);
36582 -       
36583 +
36584         return HANDLER_GO_ON;
36585  }
36586  
36587 @@ -94,107 +94,103 @@
36588  SETDEFAULTS_FUNC(mod_secdownload_set_defaults) {
36589         plugin_data *p = p_d;
36590         size_t i = 0;
36591 -       
36592 -       config_values_t cv[] = { 
36593 +
36594 +       config_values_t cv[] = {
36595                 { "secdownload.secret",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
36596                 { "secdownload.document-root",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
36597                 { "secdownload.uri-prefix",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
36598                 { "secdownload.timeout",           NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 3 */
36599                 { NULL,                            NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36600         };
36601 -       
36602 +
36603         if (!p) return HANDLER_ERROR;
36604 -       
36605 +
36606         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36607 -       
36608 +
36609         for (i = 0; i < srv->config_context->used; i++) {
36610                 plugin_config *s;
36611 -               
36612 +
36613                 s = calloc(1, sizeof(plugin_config));
36614                 s->secret        = buffer_init();
36615                 s->doc_root      = buffer_init();
36616                 s->uri_prefix    = buffer_init();
36617                 s->timeout       = 60;
36618 -               
36619 +
36620                 cv[0].destination = s->secret;
36621                 cv[1].destination = s->doc_root;
36622                 cv[2].destination = s->uri_prefix;
36623                 cv[3].destination = &(s->timeout);
36624 -               
36625 +
36626                 p->config_storage[i] = s;
36627 -       
36628 +
36629                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
36630                         return HANDLER_ERROR;
36631                 }
36632         }
36633 -       
36634 +
36635         return HANDLER_GO_ON;
36636  }
36637  
36638  /**
36639   * checks if the supplied string is a MD5 string
36640 - * 
36641 + *
36642   * @param str a possible MD5 string
36643   * @return if the supplied string is a valid MD5 string 1 is returned otherwise 0
36644   */
36645  
36646  int is_hex_len(const char *str, size_t len) {
36647         size_t i;
36648 -       
36649 +
36650         if (NULL == str) return 0;
36651 -       
36652 +
36653         for (i = 0; i < len && *str; i++, str++) {
36654                 /* illegal characters */
36655                 if (!((*str >= '0' && *str <= '9') ||
36656                       (*str >= 'a' && *str <= 'f') ||
36657 -                     (*str >= 'A' && *str <= 'F')) 
36658 +                     (*str >= 'A' && *str <= 'F'))
36659                     ) {
36660                         return 0;
36661                 }
36662         }
36663 -       
36664 +
36665         return i == len;
36666  }
36667  
36668 -#define PATCH(x) \
36669 -       p->conf.x = s->x;
36670  static int mod_secdownload_patch_connection(server *srv, connection *con, plugin_data *p) {
36671         size_t i, j;
36672         plugin_config *s = p->config_storage[0];
36673 -       
36674 -       PATCH(secret);
36675 -       PATCH(doc_root);
36676 -       PATCH(uri_prefix);
36677 -       PATCH(timeout);
36678 -       
36679 +
36680 +       PATCH_OPTION(secret);
36681 +       PATCH_OPTION(doc_root);
36682 +       PATCH_OPTION(uri_prefix);
36683 +       PATCH_OPTION(timeout);
36684 +
36685         /* skip the first, the global context */
36686         for (i = 1; i < srv->config_context->used; i++) {
36687                 data_config *dc = (data_config *)srv->config_context->data[i];
36688                 s = p->config_storage[i];
36689 -               
36690 +
36691                 /* condition didn't match */
36692                 if (!config_check_cond(srv, con, dc)) continue;
36693 -               
36694 +
36695                 /* merge config */
36696                 for (j = 0; j < dc->value->used; j++) {
36697                         data_unset *du = dc->value->data[j];
36698 -                       
36699 +
36700                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.secret"))) {
36701 -                               PATCH(secret);
36702 +                               PATCH_OPTION(secret);
36703                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.document-root"))) {
36704 -                               PATCH(doc_root);
36705 +                               PATCH_OPTION(doc_root);
36706                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.uri-prefix"))) {
36707 -                               PATCH(uri_prefix);
36708 +                               PATCH_OPTION(uri_prefix);
36709                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.timeout"))) {
36710 -                               PATCH(timeout);
36711 +                               PATCH_OPTION(timeout);
36712                         }
36713                 }
36714         }
36715 -       
36716 +
36717         return 0;
36718  }
36719 -#undef PATCH
36720 -
36721  
36722  URIHANDLER_FUNC(mod_secdownload_uri_handler) {
36723         plugin_data *p = p_d;
36724 @@ -203,88 +199,88 @@
36725         const char *rel_uri, *ts_str, *md5_str;
36726         time_t ts = 0;
36727         size_t i;
36728 -       
36729 +
36730         if (con->uri.path->used == 0) return HANDLER_GO_ON;
36731 -       
36732 +
36733         mod_secdownload_patch_connection(srv, con, p);
36734  
36735         if (buffer_is_empty(p->conf.uri_prefix)) return HANDLER_GO_ON;
36736 -       
36737 +
36738         if (buffer_is_empty(p->conf.secret)) {
36739                 log_error_write(srv, __FILE__, __LINE__, "s",
36740                                 "secdownload.secret has to be set");
36741                 return HANDLER_ERROR;
36742         }
36743 -       
36744 +
36745         if (buffer_is_empty(p->conf.doc_root)) {
36746                 log_error_write(srv, __FILE__, __LINE__, "s",
36747                                 "secdownload.document-root has to be set");
36748                 return HANDLER_ERROR;
36749         }
36750 -       
36751 -       /* 
36752 +
36753 +       /*
36754          *  /<uri-prefix>[a-f0-9]{32}/[a-f0-9]{8}/<rel-path>
36755          */
36756 -       
36757 +
36758         if (0 != strncmp(con->uri.path->ptr, p->conf.uri_prefix->ptr, p->conf.uri_prefix->used - 1)) return HANDLER_GO_ON;
36759 -       
36760 +
36761         md5_str = con->uri.path->ptr + p->conf.uri_prefix->used - 1;
36762 -       
36763 +
36764         if (!is_hex_len(md5_str, 32)) return HANDLER_GO_ON;
36765         if (*(md5_str + 32) != '/') return HANDLER_GO_ON;
36766 -       
36767 +
36768         ts_str = md5_str + 32 + 1;
36769 -       
36770 +
36771         if (!is_hex_len(ts_str, 8)) return HANDLER_GO_ON;
36772         if (*(ts_str + 8) != '/') return HANDLER_GO_ON;
36773 -       
36774 +
36775         for (i = 0; i < 8; i++) {
36776                 ts = (ts << 4) + hex2int(*(ts_str + i));
36777         }
36778 -       
36779 +
36780         /* timed-out */
36781 -       if (srv->cur_ts - ts > p->conf.timeout || 
36782 +       if (srv->cur_ts - ts > p->conf.timeout ||
36783             srv->cur_ts - ts < -p->conf.timeout) {
36784                 con->http_status = 408;
36785 -               
36786 +
36787                 return HANDLER_FINISHED;
36788         }
36789 -       
36790 +
36791         rel_uri = ts_str + 8;
36792 -       
36793 -       /* checking MD5 
36794 -        * 
36795 +
36796 +       /* checking MD5
36797 +        *
36798          * <secret><rel-path><timestamp-hex>
36799          */
36800 -       
36801 +
36802         buffer_copy_string_buffer(p->md5, p->conf.secret);
36803         buffer_append_string(p->md5, rel_uri);
36804         buffer_append_string_len(p->md5, ts_str, 8);
36805 -       
36806 +
36807         MD5_Init(&Md5Ctx);
36808         MD5_Update(&Md5Ctx, (unsigned char *)p->md5->ptr, p->md5->used - 1);
36809         MD5_Final(HA1, &Md5Ctx);
36810 -       
36811 +
36812         buffer_copy_string_hex(p->md5, (char *)HA1, 16);
36813 -       
36814 +
36815         if (0 != strncmp(md5_str, p->md5->ptr, 32)) {
36816                 con->http_status = 403;
36817 -               
36818 -               log_error_write(srv, __FILE__, __LINE__, "sss", 
36819 +
36820 +               log_error_write(srv, __FILE__, __LINE__, "sss",
36821                                 "md5 invalid:",
36822                                 md5_str, p->md5->ptr);
36823 -               
36824 +
36825                 return HANDLER_FINISHED;
36826         }
36827 -       
36828 +
36829         /* starting with the last / we should have relative-path to the docroot
36830          */
36831 -       
36832 +
36833         buffer_copy_string_buffer(con->physical.doc_root, p->conf.doc_root);
36834         buffer_copy_string(con->physical.rel_path, rel_uri);
36835         buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
36836         buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
36837 -       
36838 +
36839         return HANDLER_GO_ON;
36840  }
36841  
36842 @@ -293,13 +289,13 @@
36843  int mod_secdownload_plugin_init(plugin *p) {
36844         p->version     = LIGHTTPD_VERSION_ID;
36845         p->name        = buffer_init_string("secdownload");
36846 -       
36847 +
36848         p->init        = mod_secdownload_init;
36849         p->handle_physical  = mod_secdownload_uri_handler;
36850         p->set_defaults  = mod_secdownload_set_defaults;
36851         p->cleanup     = mod_secdownload_free;
36852 -       
36853 +
36854         p->data        = NULL;
36855 -       
36856 +
36857         return 0;
36858  }
36859 --- ../lighttpd-1.4.11/src/mod_setenv.c 2006-01-14 20:33:12.000000000 +0200
36860 +++ lighttpd-1.4.12/src/mod_setenv.c    2006-07-16 00:26:04.000000000 +0300
36861 @@ -18,25 +18,25 @@
36862  typedef struct {
36863         array *request_header;
36864         array *response_header;
36865 -       
36866 +
36867         array *environment;
36868  } plugin_config;
36869  
36870  typedef struct {
36871         PLUGIN_DATA;
36872 -       
36873 +
36874         plugin_config **config_storage;
36875 -       
36876 -       plugin_config conf; 
36877 +
36878 +       plugin_config conf;
36879  } plugin_data;
36880  
36881  static handler_ctx * handler_ctx_init() {
36882         handler_ctx * hctx;
36883 -       
36884 +
36885         hctx = calloc(1, sizeof(*hctx));
36886 -       
36887 +
36888         hctx->handled = 0;
36889 -       
36890 +
36891         return hctx;
36892  }
36893  
36894 @@ -48,36 +48,36 @@
36895  /* init the plugin data */
36896  INIT_FUNC(mod_setenv_init) {
36897         plugin_data *p;
36898 -       
36899 +
36900         p = calloc(1, sizeof(*p));
36901 -       
36902 +
36903         return p;
36904  }
36905  
36906  /* detroy the plugin data */
36907  FREE_FUNC(mod_setenv_free) {
36908         plugin_data *p = p_d;
36909 -       
36910 +
36911         UNUSED(srv);
36912  
36913         if (!p) return HANDLER_GO_ON;
36914 -       
36915 +
36916         if (p->config_storage) {
36917                 size_t i;
36918                 for (i = 0; i < srv->config_context->used; i++) {
36919                         plugin_config *s = p->config_storage[i];
36920 -                       
36921 +
36922                         array_free(s->request_header);
36923                         array_free(s->response_header);
36924                         array_free(s->environment);
36925 -                       
36926 +
36927                         free(s);
36928                 }
36929                 free(p->config_storage);
36930         }
36931 -       
36932 +
36933         free(p);
36934 -       
36935 +
36936         return HANDLER_GO_ON;
36937  }
36938  
36939 @@ -86,86 +86,83 @@
36940  SETDEFAULTS_FUNC(mod_setenv_set_defaults) {
36941         plugin_data *p = p_d;
36942         size_t i = 0;
36943 -       
36944 -       config_values_t cv[] = { 
36945 +
36946 +       config_values_t cv[] = {
36947                 { "setenv.add-request-header",  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
36948                 { "setenv.add-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
36949                 { "setenv.add-environment",     NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
36950                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36951         };
36952 -       
36953 +
36954         if (!p) return HANDLER_ERROR;
36955 -       
36956 +
36957         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36958 -       
36959 +
36960         for (i = 0; i < srv->config_context->used; i++) {
36961                 plugin_config *s;
36962 -               
36963 +
36964                 s = calloc(1, sizeof(plugin_config));
36965                 s->request_header   = array_init();
36966                 s->response_header  = array_init();
36967                 s->environment      = array_init();
36968 -               
36969 +
36970                 cv[0].destination = s->request_header;
36971                 cv[1].destination = s->response_header;
36972                 cv[2].destination = s->environment;
36973 -               
36974 +
36975                 p->config_storage[i] = s;
36976 -       
36977 +
36978                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
36979                         return HANDLER_ERROR;
36980                 }
36981         }
36982 -       
36983 +
36984         return HANDLER_GO_ON;
36985  }
36986  
36987 -#define PATCH(x) \
36988 -       p->conf.x = s->x;
36989  static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data *p) {
36990         size_t i, j;
36991         plugin_config *s = p->config_storage[0];
36992 -       
36993 -       PATCH(request_header);
36994 -       PATCH(response_header);
36995 -       PATCH(environment);
36996 -       
36997 +
36998 +       PATCH_OPTION(request_header);
36999 +       PATCH_OPTION(response_header);
37000 +       PATCH_OPTION(environment);
37001 +
37002         /* skip the first, the global context */
37003         for (i = 1; i < srv->config_context->used; i++) {
37004                 data_config *dc = (data_config *)srv->config_context->data[i];
37005                 s = p->config_storage[i];
37006 -               
37007 +
37008                 /* condition didn't match */
37009                 if (!config_check_cond(srv, con, dc)) continue;
37010 -               
37011 +
37012                 /* merge config */
37013                 for (j = 0; j < dc->value->used; j++) {
37014                         data_unset *du = dc->value->data[j];
37015 -                       
37016 +
37017                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-request-header"))) {
37018 -                               PATCH(request_header);
37019 +                               PATCH_OPTION(request_header);
37020                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-response-header"))) {
37021 -                               PATCH(response_header);
37022 +                               PATCH_OPTION(response_header);
37023                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-environment"))) {
37024 -                               PATCH(environment);
37025 +                               PATCH_OPTION(environment);
37026                         }
37027                 }
37028         }
37029 -       
37030 +
37031         return 0;
37032  }
37033 -#undef PATCH
37034  
37035  URIHANDLER_FUNC(mod_setenv_uri_handler) {
37036         plugin_data *p = p_d;
37037         size_t k;
37038         handler_ctx *hctx;
37039 -       
37040 +
37041         if (con->plugin_ctx[p->id]) {
37042                 hctx = con->plugin_ctx[p->id];
37043         } else {
37044                 hctx = handler_ctx_init();
37045 -                               
37046 +
37047                 con->plugin_ctx[p->id] = hctx;
37048         }
37049  
37050 @@ -180,52 +177,52 @@
37051         for (k = 0; k < p->conf.request_header->used; k++) {
37052                 data_string *ds = (data_string *)p->conf.request_header->data[k];
37053                 data_string *ds_dst;
37054 -               
37055 +
37056                 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
37057                         ds_dst = data_string_init();
37058                 }
37059 -               
37060 +
37061                 buffer_copy_string_buffer(ds_dst->key, ds->key);
37062                 buffer_copy_string_buffer(ds_dst->value, ds->value);
37063 -               
37064 +
37065                 array_insert_unique(con->request.headers, (data_unset *)ds_dst);
37066         }
37067 -       
37068 +
37069         for (k = 0; k < p->conf.environment->used; k++) {
37070                 data_string *ds = (data_string *)p->conf.environment->data[k];
37071                 data_string *ds_dst;
37072 -               
37073 +
37074                 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
37075                         ds_dst = data_string_init();
37076                 }
37077 -               
37078 +
37079                 buffer_copy_string_buffer(ds_dst->key, ds->key);
37080                 buffer_copy_string_buffer(ds_dst->value, ds->value);
37081 -               
37082 +
37083                 array_insert_unique(con->environment, (data_unset *)ds_dst);
37084         }
37085 -       
37086 +
37087         for (k = 0; k < p->conf.response_header->used; k++) {
37088                 data_string *ds = (data_string *)p->conf.response_header->data[k];
37089 -               
37090 +
37091                 response_header_insert(srv, con, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
37092         }
37093 -       
37094 +
37095         /* not found */
37096         return HANDLER_GO_ON;
37097  }
37098  
37099  REQUESTDONE_FUNC(mod_setenv_reset) {
37100         plugin_data *p = p_d;
37101 -       
37102 +
37103         UNUSED(srv);
37104 -       
37105 +
37106         if (con->plugin_ctx[p->id]) {
37107                 handler_ctx_free(con->plugin_ctx[p->id]);
37108                 con->plugin_ctx[p->id] = NULL;
37109         }
37110  
37111 -       return HANDLER_GO_ON;   
37112 +       return HANDLER_GO_ON;
37113  }
37114  
37115  /* this function is called at dlopen() time and inits the callbacks */
37116 @@ -233,15 +230,15 @@
37117  int mod_setenv_plugin_init(plugin *p) {
37118         p->version     = LIGHTTPD_VERSION_ID;
37119         p->name        = buffer_init_string("setenv");
37120 -       
37121 +
37122         p->init        = mod_setenv_init;
37123         p->handle_uri_clean  = mod_setenv_uri_handler;
37124         p->set_defaults  = mod_setenv_set_defaults;
37125         p->cleanup     = mod_setenv_free;
37126 -       
37127 +
37128         p->handle_request_done  = mod_setenv_reset;
37129  
37130         p->data        = NULL;
37131 -       
37132 +
37133         return 0;
37134  }
37135 --- ../lighttpd-1.4.11/src/mod_simple_vhost.c   2005-11-18 15:16:13.000000000 +0200
37136 +++ lighttpd-1.4.12/src/mod_simple_vhost.c      2006-07-16 00:26:04.000000000 +0300
37137 @@ -10,6 +10,8 @@
37138  
37139  #include "plugin.h"
37140  
37141 +#include "sys-files.h"
37142 +
37143  #ifdef HAVE_CONFIG_H
37144  #include "config.h"
37145  #endif
37146 @@ -18,7 +20,7 @@
37147         buffer *server_root;
37148         buffer *default_host;
37149         buffer *document_root;
37150 -       
37151 +
37152         buffer *docroot_cache_key;
37153         buffer *docroot_cache_value;
37154         buffer *docroot_cache_servername;
37155 @@ -28,138 +30,138 @@
37156  
37157  typedef struct {
37158         PLUGIN_DATA;
37159 -       
37160 +
37161         buffer *doc_root;
37162 -       
37163 +
37164         plugin_config **config_storage;
37165 -       plugin_config conf; 
37166 +       plugin_config conf;
37167  } plugin_data;
37168  
37169  INIT_FUNC(mod_simple_vhost_init) {
37170         plugin_data *p;
37171 -       
37172 +
37173         p = calloc(1, sizeof(*p));
37174 -       
37175 +
37176         p->doc_root = buffer_init();
37177 -       
37178 +
37179         return p;
37180  }
37181  
37182  FREE_FUNC(mod_simple_vhost_free) {
37183         plugin_data *p = p_d;
37184 -       
37185 +
37186         UNUSED(srv);
37187  
37188         if (!p) return HANDLER_GO_ON;
37189 -       
37190 +
37191         if (p->config_storage) {
37192                 size_t i;
37193                 for (i = 0; i < srv->config_context->used; i++) {
37194                         plugin_config *s = p->config_storage[i];
37195 -                       
37196 +
37197                         buffer_free(s->document_root);
37198                         buffer_free(s->default_host);
37199                         buffer_free(s->server_root);
37200 -                       
37201 +
37202                         buffer_free(s->docroot_cache_key);
37203                         buffer_free(s->docroot_cache_value);
37204                         buffer_free(s->docroot_cache_servername);
37205 -                       
37206 +
37207                         free(s);
37208                 }
37209 -       
37210 +
37211                 free(p->config_storage);
37212         }
37213 -       
37214 +
37215         buffer_free(p->doc_root);
37216 -       
37217 +
37218         free(p);
37219 -       
37220 +
37221         return HANDLER_GO_ON;
37222  }
37223  
37224  SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) {
37225         plugin_data *p = p_d;
37226         size_t i;
37227 -       
37228 -       config_values_t cv[] = { 
37229 +
37230 +       config_values_t cv[] = {
37231                 { "simple-vhost.server-root",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
37232                 { "simple-vhost.default-host",      NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
37233                 { "simple-vhost.document-root",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
37234                 { "simple-vhost.debug",             NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
37235                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37236         };
37237 -       
37238 +
37239         if (!p) return HANDLER_ERROR;
37240 -       
37241 +
37242         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37243 -       
37244 +
37245         for (i = 0; i < srv->config_context->used; i++) {
37246                 plugin_config *s;
37247 -               
37248 +
37249                 s = calloc(1, sizeof(plugin_config));
37250 -               
37251 +
37252                 s->server_root = buffer_init();
37253                 s->default_host = buffer_init();
37254                 s->document_root = buffer_init();
37255 -               
37256 +
37257                 s->docroot_cache_key = buffer_init();
37258                 s->docroot_cache_value = buffer_init();
37259                 s->docroot_cache_servername = buffer_init();
37260  
37261                 s->debug = 0;
37262 -               
37263 +
37264                 cv[0].destination = s->server_root;
37265                 cv[1].destination = s->default_host;
37266                 cv[2].destination = s->document_root;
37267                 cv[3].destination = &(s->debug);
37268 -               
37269 -               
37270 +
37271 +
37272                 p->config_storage[i] = s;
37273 -               
37274 +
37275                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37276                         return HANDLER_ERROR;
37277                 }
37278         }
37279 -       
37280 +
37281         return HANDLER_GO_ON;
37282  }
37283  
37284  static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) {
37285         stat_cache_entry *sce = NULL;
37286 -       
37287 +
37288         buffer_prepare_copy(out, 128);
37289  
37290         if (p->conf.server_root->used) {
37291                 buffer_copy_string_buffer(out, p->conf.server_root);
37292 -               
37293 +
37294                 if (host->used) {
37295                         /* a hostname has to start with a alpha-numerical character
37296                          * and must not contain a slash "/"
37297                          */
37298                         char *dp;
37299 -                       
37300 -                       BUFFER_APPEND_SLASH(out);
37301 -                       
37302 +
37303 +                       PATHNAME_APPEND_SLASH(out);
37304 +
37305                         if (NULL == (dp = strchr(host->ptr, ':'))) {
37306                                 buffer_append_string_buffer(out, host);
37307                         } else {
37308                                 buffer_append_string_len(out, host->ptr, dp - host->ptr);
37309                         }
37310                 }
37311 -               BUFFER_APPEND_SLASH(out);
37312 -               
37313 +               PATHNAME_APPEND_SLASH(out);
37314 +
37315                 if (p->conf.document_root->used > 2 && p->conf.document_root->ptr[0] == '/') {
37316                         buffer_append_string_len(out, p->conf.document_root->ptr + 1, p->conf.document_root->used - 2);
37317                 } else {
37318                         buffer_append_string_buffer(out, p->conf.document_root);
37319 -                       BUFFER_APPEND_SLASH(out);
37320 +                       PATHNAME_APPEND_SLASH(out);
37321                 }
37322         } else {
37323                 buffer_copy_string_buffer(out, con->conf.document_root);
37324 -               BUFFER_APPEND_SLASH(out);
37325 +               PATHNAME_APPEND_SLASH(out);
37326         }
37327 -       
37328 +
37329         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) {
37330                 if (p->conf.debug) {
37331                         log_error_write(srv, __FILE__, __LINE__, "sb",
37332 @@ -169,57 +171,53 @@
37333         } else if (!S_ISDIR(sce->st.st_mode)) {
37334                 return -1;
37335         }
37336 -       
37337 +
37338         return 0;
37339  }
37340  
37341 -
37342 -#define PATCH(x) \
37343 -       p->conf.x = s->x;
37344  static int mod_simple_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
37345         size_t i, j;
37346         plugin_config *s = p->config_storage[0];
37347 -       
37348 -       PATCH(server_root);
37349 -       PATCH(default_host);
37350 -       PATCH(document_root);
37351 -       
37352 -       PATCH(docroot_cache_key);
37353 -       PATCH(docroot_cache_value);
37354 -       PATCH(docroot_cache_servername);
37355  
37356 -       PATCH(debug);
37357 -       
37358 +       PATCH_OPTION(server_root);
37359 +       PATCH_OPTION(default_host);
37360 +       PATCH_OPTION(document_root);
37361 +
37362 +       PATCH_OPTION(docroot_cache_key);
37363 +       PATCH_OPTION(docroot_cache_value);
37364 +       PATCH_OPTION(docroot_cache_servername);
37365 +
37366 +       PATCH_OPTION(debug);
37367 +
37368         /* skip the first, the global context */
37369         for (i = 1; i < srv->config_context->used; i++) {
37370                 data_config *dc = (data_config *)srv->config_context->data[i];
37371                 s = p->config_storage[i];
37372 -               
37373 +
37374                 /* condition didn't match */
37375                 if (!config_check_cond(srv, con, dc)) continue;
37376 -               
37377 +
37378                 /* merge config */
37379                 for (j = 0; j < dc->value->used; j++) {
37380                         data_unset *du = dc->value->data[j];
37381 -                       
37382 +
37383                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.server-root"))) {
37384 -                               PATCH(server_root);
37385 -                               PATCH(docroot_cache_key);
37386 -                               PATCH(docroot_cache_value);
37387 -                               PATCH(docroot_cache_servername);
37388 +                               PATCH_OPTION(server_root);
37389 +                               PATCH_OPTION(docroot_cache_key);
37390 +                               PATCH_OPTION(docroot_cache_value);
37391 +                               PATCH_OPTION(docroot_cache_servername);
37392                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.default-host"))) {
37393 -                               PATCH(default_host);
37394 +                               PATCH_OPTION(default_host);
37395                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.document-root"))) {
37396 -                               PATCH(document_root);
37397 +                               PATCH_OPTION(document_root);
37398                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.debug"))) {
37399 -                               PATCH(debug);
37400 +                               PATCH_OPTION(debug);
37401                         }
37402                 }
37403         }
37404 -       
37405 +
37406         return 0;
37407  }
37408 -#undef PATCH
37409  
37410  static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_data) {
37411         plugin_data *p = p_data;
37412 @@ -227,12 +225,12 @@
37413         /*
37414          * cache the last successfull translation from hostname (authority) to docroot
37415          * - this saves us a stat() call
37416 -        * 
37417 +        *
37418          */
37419 -       
37420 +
37421         mod_simple_vhost_patch_connection(srv, con, p);
37422 -       
37423 -       if (p->conf.docroot_cache_key->used && 
37424 +
37425 +       if (p->conf.docroot_cache_key->used &&
37426             con->uri.authority->used &&
37427             buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) {
37428                 /* cache hit */
37429 @@ -243,8 +241,8 @@
37430                 if ((con->uri.authority->used == 0) ||
37431                     build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) {
37432                         /* not found, fallback the default-host */
37433 -                       if (build_doc_root(srv, con, p, 
37434 -                                          p->doc_root, 
37435 +                       if (build_doc_root(srv, con, p,
37436 +                                          p->doc_root,
37437                                            p->conf.default_host)) {
37438                                 return HANDLER_GO_ON;
37439                         } else {
37440 @@ -253,15 +251,15 @@
37441                 } else {
37442                         buffer_copy_string_buffer(con->server_name, con->uri.authority);
37443                 }
37444 -               
37445 +
37446                 /* copy to cache */
37447                 buffer_copy_string_buffer(p->conf.docroot_cache_key,        con->uri.authority);
37448                 buffer_copy_string_buffer(p->conf.docroot_cache_value,      p->doc_root);
37449                 buffer_copy_string_buffer(p->conf.docroot_cache_servername, con->server_name);
37450 -               
37451 +
37452                 buffer_copy_string_buffer(con->physical.doc_root, p->doc_root);
37453         }
37454 -       
37455 +
37456         return HANDLER_GO_ON;
37457  }
37458  
37459 @@ -269,13 +267,13 @@
37460  int mod_simple_vhost_plugin_init(plugin *p) {
37461         p->version     = LIGHTTPD_VERSION_ID;
37462         p->name        = buffer_init_string("simple_vhost");
37463 -       
37464 +
37465         p->init        = mod_simple_vhost_init;
37466         p->set_defaults = mod_simple_vhost_set_defaults;
37467         p->handle_docroot  = mod_simple_vhost_docroot;
37468         p->cleanup     = mod_simple_vhost_free;
37469 -       
37470 +
37471         p->data        = NULL;
37472 -       
37473 +
37474         return 0;
37475  }
37476 --- ../lighttpd-1.4.11/src/mod_skeleton.c       2005-10-02 18:30:51.000000000 +0300
37477 +++ lighttpd-1.4.12/src/mod_skeleton.c  2006-07-16 00:26:03.000000000 +0300
37478 @@ -14,13 +14,13 @@
37479  
37480  /**
37481   * this is a skeleton for a lighttpd plugin
37482 - * 
37483 + *
37484   * just replaces every occurance of 'skeleton' by your plugin name
37485 - * 
37486 + *
37487   * e.g. in vim:
37488 - * 
37489 + *
37490   *   :%s/skeleton/myhandler/
37491 - * 
37492 + *
37493   */
37494  
37495  
37496 @@ -33,12 +33,12 @@
37497  
37498  typedef struct {
37499         PLUGIN_DATA;
37500 -       
37501 +
37502         buffer *match_buf;
37503 -       
37504 +
37505         plugin_config **config_storage;
37506 -       
37507 -       plugin_config conf; 
37508 +
37509 +       plugin_config conf;
37510  } plugin_data;
37511  
37512  typedef struct {
37513 @@ -47,36 +47,36 @@
37514  
37515  static handler_ctx * handler_ctx_init() {
37516         handler_ctx * hctx;
37517 -       
37518 +
37519         hctx = calloc(1, sizeof(*hctx));
37520 -       
37521 +
37522         return hctx;
37523  }
37524  
37525  static void handler_ctx_free(handler_ctx *hctx) {
37526 -       
37527 +
37528         free(hctx);
37529  }
37530  
37531  /* init the plugin data */
37532  INIT_FUNC(mod_skeleton_init) {
37533         plugin_data *p;
37534 -       
37535 +
37536         p = calloc(1, sizeof(*p));
37537 -       
37538 +
37539         p->match_buf = buffer_init();
37540 -       
37541 +
37542         return p;
37543  }
37544  
37545  /* detroy the plugin data */
37546  FREE_FUNC(mod_skeleton_free) {
37547         plugin_data *p = p_d;
37548 -       
37549 +
37550         UNUSED(srv);
37551  
37552         if (!p) return HANDLER_GO_ON;
37553 -       
37554 +
37555         if (p->config_storage) {
37556                 size_t i;
37557  
37558 @@ -84,18 +84,18 @@
37559                         plugin_config *s = p->config_storage[i];
37560  
37561                         if (!s) continue;
37562 -                       
37563 +
37564                         array_free(s->match);
37565 -                       
37566 +
37567                         free(s);
37568                 }
37569                 free(p->config_storage);
37570         }
37571 -       
37572 +
37573         buffer_free(p->match_buf);
37574 -       
37575 +
37576         free(p);
37577 -       
37578 +
37579         return HANDLER_GO_ON;
37580  }
37581  
37582 @@ -104,91 +104,88 @@
37583  SETDEFAULTS_FUNC(mod_skeleton_set_defaults) {
37584         plugin_data *p = p_d;
37585         size_t i = 0;
37586 -       
37587 -       config_values_t cv[] = { 
37588 +
37589 +       config_values_t cv[] = {
37590                 { "skeleton.array",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
37591                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37592         };
37593 -       
37594 +
37595         if (!p) return HANDLER_ERROR;
37596 -       
37597 +
37598         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37599 -       
37600 +
37601         for (i = 0; i < srv->config_context->used; i++) {
37602                 plugin_config *s;
37603 -               
37604 +
37605                 s = calloc(1, sizeof(plugin_config));
37606                 s->match    = array_init();
37607 -               
37608 +
37609                 cv[0].destination = s->match;
37610 -               
37611 +
37612                 p->config_storage[i] = s;
37613 -       
37614 +
37615                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37616                         return HANDLER_ERROR;
37617                 }
37618         }
37619 -       
37620 +
37621         return HANDLER_GO_ON;
37622  }
37623  
37624 -#define PATCH(x) \
37625 -       p->conf.x = s->x;
37626  static int mod_skeleton_patch_connection(server *srv, connection *con, plugin_data *p) {
37627         size_t i, j;
37628         plugin_config *s = p->config_storage[0];
37629 -       
37630 -       PATCH(match);
37631 -       
37632 +
37633 +       PATCH_OPTION(match);
37634 +
37635         /* skip the first, the global context */
37636         for (i = 1; i < srv->config_context->used; i++) {
37637                 data_config *dc = (data_config *)srv->config_context->data[i];
37638                 s = p->config_storage[i];
37639 -               
37640 +
37641                 /* condition didn't match */
37642                 if (!config_check_cond(srv, con, dc)) continue;
37643 -               
37644 +
37645                 /* merge config */
37646                 for (j = 0; j < dc->value->used; j++) {
37647                         data_unset *du = dc->value->data[j];
37648 -                       
37649 +
37650                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("skeleton.array"))) {
37651 -                               PATCH(match);
37652 +                               PATCH_OPTION(match);
37653                         }
37654                 }
37655         }
37656 -       
37657 +
37658         return 0;
37659  }
37660 -#undef PATCH
37661  
37662  URIHANDLER_FUNC(mod_skeleton_uri_handler) {
37663         plugin_data *p = p_d;
37664         int s_len;
37665         size_t k, i;
37666 -       
37667 +
37668         UNUSED(srv);
37669  
37670         if (con->uri.path->used == 0) return HANDLER_GO_ON;
37671 -       
37672 +
37673         mod_skeleton_patch_connection(srv, con, p);
37674  
37675         s_len = con->uri.path->used - 1;
37676 -       
37677 +
37678         for (k = 0; k < p->conf.match->used; k++) {
37679                 data_string *ds = (data_string *)p->conf.match->data[k];
37680                 int ct_len = ds->value->used - 1;
37681 -               
37682 +
37683                 if (ct_len > s_len) continue;
37684                 if (ds->value->used == 0) continue;
37685 -               
37686 +
37687                 if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
37688                         con->http_status = 403;
37689 -       
37690 +
37691                         return HANDLER_FINISHED;
37692                 }
37693         }
37694 -       
37695 +
37696         /* not found */
37697         return HANDLER_GO_ON;
37698  }
37699 @@ -198,13 +195,13 @@
37700  int mod_skeleton_plugin_init(plugin *p) {
37701         p->version     = LIGHTTPD_VERSION_ID;
37702         p->name        = buffer_init_string("skeleton");
37703 -       
37704 +
37705         p->init        = mod_skeleton_init;
37706         p->handle_uri_clean  = mod_skeleton_uri_handler;
37707         p->set_defaults  = mod_skeleton_set_defaults;
37708         p->cleanup     = mod_skeleton_free;
37709 -       
37710 +
37711         p->data        = NULL;
37712 -       
37713 +
37714         return 0;
37715  }
37716 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.c 1970-01-01 03:00:00.000000000 +0300
37717 +++ lighttpd-1.4.12/src/mod_sql_vhost_core.c    2006-07-20 00:57:20.000000000 +0300
37718 @@ -0,0 +1,211 @@
37719 +#include <stdio.h>
37720 +#include <errno.h>
37721 +#include <fcntl.h>
37722 +#include <string.h>
37723 +
37724 +#ifdef HAVE_CONFIG_H
37725 +#include "config.h"
37726 +#endif
37727 +
37728 +#include "plugin.h"
37729 +#include "log.h"
37730 +
37731 +#include "stat_cache.h"
37732 +
37733 +#include "mod_sql_vhost_core.h"
37734 +
37735 +#define plugin_data mod_sql_vhost_core_plugin_data
37736 +#define plugin_config mod_sql_vhost_core_plugin_config
37737 +
37738 +/* init the plugin data */
37739 +INIT_FUNC(mod_sql_vhost_core_init) {
37740 +       plugin_data *p;
37741 +
37742 +       p = calloc(1, sizeof(*p));
37743 +
37744 +       p->docroot = buffer_init();
37745 +       p->host = buffer_init();
37746 +
37747 +       return p;
37748 +}
37749 +
37750 +/* cleanup the plugin data */
37751 +SERVER_FUNC(mod_sql_vhost_core_cleanup) {
37752 +       plugin_data *p = p_d;
37753 +
37754 +       UNUSED(srv);
37755 +
37756 +       if (!p) return HANDLER_GO_ON;
37757 +
37758 +       if (p->config_storage) {
37759 +               size_t i;
37760 +               for (i = 0; i < srv->config_context->used; i++) {
37761 +                       plugin_config *s = p->config_storage[i];
37762 +
37763 +                       if (!s) continue;
37764 +
37765 +                       buffer_free(s->db);
37766 +                       buffer_free(s->user);
37767 +                       buffer_free(s->pass);
37768 +                       buffer_free(s->sock);
37769 +                       buffer_free(s->backend);
37770 +                       buffer_free(s->hostname);
37771 +                       buffer_free(s->select_vhost);
37772 +
37773 +                       free(s);
37774 +               }
37775 +               free(p->config_storage);
37776 +       }
37777 +       buffer_free(p->docroot);
37778 +       buffer_free(p->host);
37779 +
37780 +       free(p);
37781 +
37782 +       return HANDLER_GO_ON;
37783 +}
37784 +
37785 +/* set configuration values */
37786 +SERVER_FUNC(mod_sql_vhost_core_set_defaults) {
37787 +       plugin_data *p = p_d;
37788 +
37789 +       size_t i = 0;
37790 +
37791 +       config_values_t cv[] = {
37792 +               { "sql-vhost.db",       NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 0 * e.g. vhost */
37793 +               { "sql-vhost.user",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 1 * lighty */
37794 +               { "sql-vhost.pass",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 2 * secrect */
37795 +               { "sql-vhost.sock",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 3 * /tmp/mysql.sock */
37796 +               { "sql-vhost.select-vhost", NULL, T_CONFIG_STRING,      T_CONFIG_SCOPE_SERVER }, /* 4 * SELECT ... FROM hosts WHERE hostname = ? */
37797 +               { "sql-vhost.hostname", NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 5 * 127.0.0.1 */
37798 +               { "sql-vhost.port",     NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER }, /* 6 * 3306 */
37799 +               { "sql-vhost.backend",  NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 7 * mysql */
37800 +
37801 +               /* backward compat */
37802 +               { "mysql-vhost.db",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 8 == 0 */
37803 +               { "mysql-vhost.user",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 9 == 1 */
37804 +               { "mysql-vhost.pass",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 10 == 2 */
37805 +               { "mysql-vhost.sock",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 11 == 3 */
37806 +               { "mysql-vhost.sql",    NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 12 == 4 */
37807 +               { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER }, /* 13 == 5 */
37808 +               { "mysql-vhost.port",   NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER }, /* 14 == 6 */
37809 +
37810 +                { NULL,                        NULL, T_CONFIG_UNSET,   T_CONFIG_SCOPE_UNSET }
37811 +        };
37812 +
37813 +       p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37814 +
37815 +       for (i = 0; i < srv->config_context->used; i++) {
37816 +               plugin_config *s;
37817 +
37818 +               s = calloc(1, sizeof(plugin_config));
37819 +               s->db = buffer_init();
37820 +               s->user = buffer_init();
37821 +               s->pass = buffer_init();
37822 +               s->sock = buffer_init();
37823 +               s->hostname = buffer_init();
37824 +               s->backend = buffer_init();
37825 +               s->port   = 0;               /* default port for mysql */
37826 +               s->select_vhost = buffer_init();
37827 +               s->backend_data = NULL;
37828 +
37829 +               cv[0].destination = s->db;
37830 +               cv[1].destination = s->user;
37831 +               cv[2].destination = s->pass;
37832 +               cv[3].destination = s->sock;
37833 +               cv[4].destination = s->select_vhost;
37834 +               cv[5].destination = s->hostname;
37835 +               cv[6].destination = &(s->port);
37836 +               cv[7].destination = s->backend;
37837 +
37838 +               /* backend compat */
37839 +               cv[8].destination = cv[0].destination;
37840 +               cv[9].destination = cv[1].destination;
37841 +               cv[10].destination = cv[2].destination;
37842 +               cv[11].destination = cv[3].destination;
37843 +               cv[12].destination = cv[4].destination;
37844 +               cv[13].destination = cv[5].destination;
37845 +               cv[14].destination = cv[6].destination;
37846 +
37847 +               p->config_storage[i] = s;
37848 +
37849 +               if (config_insert_values_global(srv,
37850 +                       ((data_config *)srv->config_context->data[i])->value,
37851 +                       cv)) return HANDLER_ERROR;
37852 +
37853 +               /* we only parse the config, the backend plugin will patch itself into the plugin-struct */
37854 +       }
37855 +
37856 +        return HANDLER_GO_ON;
37857 +}
37858 +
37859 +static int mod_sql_vhost_core_patch_connection(server *srv, connection *con, plugin_data *p) {
37860 +       size_t i;
37861 +       plugin_config *s = p->config_storage[0];
37862 +
37863 +       PATCH_OPTION(backend_data);
37864 +       PATCH_OPTION(get_vhost);
37865 +
37866 +       /* skip the first, the global context */
37867 +       for (i = 1; i < srv->config_context->used; i++) {
37868 +               data_config *dc = (data_config *)srv->config_context->data[i];
37869 +               s = p->config_storage[i];
37870 +
37871 +               /* condition didn't match */
37872 +               if (!config_check_cond(srv, con, dc)) continue;
37873 +
37874 +               if (s->backend_data) {
37875 +                       PATCH_OPTION(backend_data);
37876 +                       PATCH_OPTION(get_vhost);
37877 +               }
37878 +       }
37879 +
37880 +       return 0;
37881 +}
37882 +
37883 +/* handle document root request */
37884 +CONNECTION_FUNC(mod_sql_vhost_core_handle_docroot) {
37885 +       plugin_data *p = p_d;
37886 +       stat_cache_entry *sce;
37887 +
37888 +       /* no host specified? */
37889 +       if (!con->uri.authority->used) return HANDLER_GO_ON;
37890 +
37891 +       mod_sql_vhost_core_patch_connection(srv, con, p);
37892 +
37893 +       /* do we have backend ? */
37894 +       if (!p->conf.get_vhost) return HANDLER_GO_ON;
37895 +
37896 +       /* ask the backend for the data */
37897 +       if (0 != p->conf.get_vhost(srv, con, p->conf.backend_data, p->docroot, p->host)) {
37898 +               return HANDLER_GO_ON;
37899 +       }
37900 +
37901 +       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->docroot, &sce)) {
37902 +               log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->docroot);
37903 +               return HANDLER_GO_ON;
37904 +       }
37905 +        if (!S_ISDIR(sce->st.st_mode)) {
37906 +               log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->docroot);
37907 +               return HANDLER_GO_ON;
37908 +       }
37909 +
37910 +       buffer_copy_string_buffer(con->server_name, p->host);
37911 +       buffer_copy_string_buffer(con->physical.doc_root, p->docroot);
37912 +
37913 +       return HANDLER_GO_ON;
37914 +}
37915 +
37916 +/* this function is called at dlopen() time and inits the callbacks */
37917 +int mod_sql_vhost_core_plugin_init(plugin *p) {
37918 +       p->version     = LIGHTTPD_VERSION_ID;
37919 +       p->name                         = buffer_init_string("mod_sql_vhost_core");
37920 +
37921 +       p->init                         = mod_sql_vhost_core_init;
37922 +       p->cleanup                      = mod_sql_vhost_core_cleanup;
37923 +
37924 +       p->set_defaults                 = mod_sql_vhost_core_set_defaults;
37925 +       p->handle_docroot               = mod_sql_vhost_core_handle_docroot;
37926 +
37927 +       return 0;
37928 +}
37929 +
37930 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.h 1970-01-01 03:00:00.000000000 +0300
37931 +++ lighttpd-1.4.12/src/mod_sql_vhost_core.h    2006-07-16 00:26:04.000000000 +0300
37932 @@ -0,0 +1,49 @@
37933 +#ifndef _MOD_SQL_VHOST_CORE_H_
37934 +#define _MOD_SQL_VHOST_CORE_H_
37935 +
37936 +#include "buffer.h"
37937 +#include "plugin.h"
37938 +
37939 +#define SQLVHOST_BACKEND_GETVHOST_PARAMS \
37940 +       (server *srv, connection *con, void *p_d, buffer *docroot, buffer *host)
37941 +
37942 +#define SQLVHOST_BACKEND_GETVHOST_RETVAL handler_t
37943 +
37944 +#define SQLVHOST_BACKEND_GETVHOST(name) \
37945 +       SQLVHOST_BACKEND_GETVHOST_RETVAL name SQLVHOST_BACKEND_GETVHOST_PARAMS
37946 +
37947 +#define SQLVHOST_BACKEND_GETVHOST_PTR(name) \
37948 +       SQLVHOST_BACKEND_GETVHOST_RETVAL (* name)SQLVHOST_BACKEND_GETVHOST_PARAMS
37949 +
37950 +typedef struct {
37951 +       buffer  *db;
37952 +       buffer  *user;
37953 +       buffer  *pass;
37954 +       buffer  *sock;
37955 +
37956 +       buffer  *hostname;
37957 +       unsigned short port;
37958 +
37959 +       buffer  *backend;
37960 +       void *backend_data;
37961 +
37962 +       buffer *select_vhost;
37963 +
37964 +       SQLVHOST_BACKEND_GETVHOST_PTR(get_vhost);
37965 +} mod_sql_vhost_core_plugin_config;
37966 +
37967 +/* global plugin data */
37968 +typedef struct {
37969 +       PLUGIN_DATA;
37970 +
37971 +       buffer  *docroot;
37972 +       buffer  *host;
37973 +
37974 +       mod_sql_vhost_core_plugin_config **config_storage;
37975 +
37976 +       mod_sql_vhost_core_plugin_config conf;
37977 +} mod_sql_vhost_core_plugin_data;
37978 +
37979 +
37980 +
37981 +#endif
37982 --- ../lighttpd-1.4.11/src/mod_ssi.c    2006-03-04 17:09:48.000000000 +0200
37983 +++ lighttpd-1.4.12/src/mod_ssi.c       2006-07-16 00:26:04.000000000 +0300
37984 @@ -6,7 +6,6 @@
37985  #include <string.h>
37986  #include <errno.h>
37987  #include <time.h>
37988 -#include <unistd.h>
37989  
37990  #include "base.h"
37991  #include "log.h"
37992 @@ -23,6 +22,8 @@
37993  #include "inet_ntop_cache.h"
37994  
37995  #include "sys-socket.h"
37996 +#include "sys-strings.h"
37997 +#include "sys-files.h"
37998  
37999  #ifdef HAVE_PWD_H
38000  #include <pwd.h>
38001 @@ -39,15 +40,15 @@
38002  /* init the plugin data */
38003  INIT_FUNC(mod_ssi_init) {
38004         plugin_data *p;
38005 -       
38006 +
38007         p = calloc(1, sizeof(*p));
38008 -       
38009 +
38010         p->timefmt = buffer_init();
38011         p->stat_fn = buffer_init();
38012 -       
38013 +
38014         p->ssi_vars = array_init();
38015         p->ssi_cgi_env = array_init();
38016 -       
38017 +
38018         return p;
38019  }
38020  
38021 @@ -55,21 +56,21 @@
38022  FREE_FUNC(mod_ssi_free) {
38023         plugin_data *p = p_d;
38024         UNUSED(srv);
38025 -       
38026 +
38027         if (!p) return HANDLER_GO_ON;
38028 -       
38029 +
38030         if (p->config_storage) {
38031                 size_t i;
38032                 for (i = 0; i < srv->config_context->used; i++) {
38033                         plugin_config *s = p->config_storage[i];
38034 -                       
38035 +
38036                         array_free(s->ssi_extension);
38037 -                       
38038 +
38039                         free(s);
38040                 }
38041                 free(p->config_storage);
38042         }
38043 -       
38044 +
38045         array_free(p->ssi_vars);
38046         array_free(p->ssi_cgi_env);
38047  #ifdef HAVE_PCRE_H
38048 @@ -77,9 +78,9 @@
38049  #endif
38050         buffer_free(p->timefmt);
38051         buffer_free(p->stat_fn);
38052 -       
38053 +
38054         free(p);
38055 -       
38056 +
38057         return HANDLER_GO_ON;
38058  }
38059  
38060 @@ -92,36 +93,36 @@
38061         const char *errptr;
38062         int erroff;
38063  #endif
38064 -       
38065 -       config_values_t cv[] = { 
38066 +
38067 +       config_values_t cv[] = {
38068                 { "ssi.extension",              NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
38069                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
38070         };
38071 -       
38072 +
38073         if (!p) return HANDLER_ERROR;
38074 -       
38075 +
38076         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
38077 -       
38078 +
38079         for (i = 0; i < srv->config_context->used; i++) {
38080                 plugin_config *s;
38081 -               
38082 +
38083                 s = calloc(1, sizeof(plugin_config));
38084                 s->ssi_extension  = array_init();
38085 -               
38086 +
38087                 cv[0].destination = s->ssi_extension;
38088 -               
38089 +
38090                 p->config_storage[i] = s;
38091 -       
38092 +
38093                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
38094                         return HANDLER_ERROR;
38095                 }
38096         }
38097 -       
38098 +
38099  #ifdef HAVE_PCRE_H
38100         /* allow 2 params */
38101         if (NULL == (p->ssi_regex = pcre_compile("<!--#([a-z]+)\\s+(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?-->", 0, &errptr, &erroff, NULL))) {
38102                 log_error_write(srv, __FILE__, __LINE__, "sds",
38103 -                               "ssi: pcre ", 
38104 +                               "ssi: pcre ",
38105                                 erroff, errptr);
38106                 return HANDLER_ERROR;
38107         }
38108 @@ -130,52 +131,52 @@
38109                         "mod_ssi: pcre support is missing, please recompile with pcre support or remove mod_ssi from the list of modules");
38110         return HANDLER_ERROR;
38111  #endif
38112 -       
38113 +
38114         return HANDLER_GO_ON;
38115  }
38116  
38117  int ssi_env_add(array *env, const char *key, const char *val) {
38118         data_string *ds;
38119 -                       
38120 +
38121         if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
38122                 ds = data_string_init();
38123         }
38124         buffer_copy_string(ds->key,   key);
38125         buffer_copy_string(ds->value, val);
38126 -       
38127 +
38128         array_insert_unique(env, (data_unset *)ds);
38129 -       
38130 +
38131         return 0;
38132  }
38133  
38134  /**
38135   *
38136   *  the next two functions are take from fcgi.c
38137 - * 
38138 + *
38139   */
38140  
38141  static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
38142         size_t i;
38143 -       
38144 +
38145         for (i = 0; i < con->request.headers->used; i++) {
38146                 data_string *ds;
38147 -               
38148 +
38149                 ds = (data_string *)con->request.headers->data[i];
38150 -               
38151 +
38152                 if (ds->value->used && ds->key->used) {
38153                         size_t j;
38154                         buffer_reset(srv->tmp_buf);
38155 -                       
38156 +
38157                         /* don't forward the Authorization: Header */
38158                         if (0 == strcasecmp(ds->key->ptr, "AUTHORIZATION")) {
38159                                 continue;
38160                         }
38161 -                       
38162 +
38163                         if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
38164                                 buffer_copy_string(srv->tmp_buf, "HTTP_");
38165                                 srv->tmp_buf->used--;
38166                         }
38167 -                       
38168 +
38169                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
38170                         for (j = 0; j < ds->key->used - 1; j++) {
38171                                 char c = '_';
38172 @@ -189,33 +190,33 @@
38173                                 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
38174                         }
38175                         srv->tmp_buf->ptr[srv->tmp_buf->used] = '\0';
38176 -                       
38177 +
38178                         ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
38179                 }
38180         }
38181 -       
38182 +
38183         return 0;
38184  }
38185  
38186  static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
38187         char buf[32];
38188 -       
38189 +
38190         server_socket *srv_sock = con->srv_socket;
38191 -       
38192 +
38193  #ifdef HAVE_IPV6
38194         char b2[INET6_ADDRSTRLEN + 1];
38195  #endif
38196  
38197  #define CONST_STRING(x) \
38198                 x
38199 -       
38200 +
38201         array_reset(p->ssi_cgi_env);
38202 -       
38203 +
38204         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_SOFTWARE"), PACKAGE_NAME"/"PACKAGE_VERSION);
38205         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_NAME"),
38206  #ifdef HAVE_IPV6
38207 -                    inet_ntop(srv_sock->addr.plain.sa_family, 
38208 -                              srv_sock->addr.plain.sa_family == AF_INET6 ? 
38209 +                    inet_ntop(srv_sock->addr.plain.sa_family,
38210 +                              srv_sock->addr.plain.sa_family == AF_INET6 ?
38211                                (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
38212                                (const void *) &(srv_sock->addr.ipv4.sin_addr),
38213                                b2, sizeof(b2)-1)
38214 @@ -224,28 +225,28 @@
38215  #endif
38216                      );
38217         ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1");
38218 -               
38219 -       ltostr(buf, 
38220 +
38221 +       ltostr(buf,
38222  #ifdef HAVE_IPV6
38223                ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
38224  #else
38225                ntohs(srv_sock->addr.ipv4.sin_port)
38226  #endif
38227                );
38228 -       
38229 +
38230         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PORT"), buf);
38231 -       
38232 +
38233         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_ADDR"),
38234                     inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
38235 -       
38236 +
38237         if (con->authed_user->used) {
38238                 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_USER"),
38239                              con->authed_user->ptr);
38240         }
38241 -       
38242 +
38243         if (con->request.content_length > 0) {
38244                 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
38245 -               
38246 +
38247                 /* request.content_length < SSIZE_MAX, see request.c */
38248                 ltostr(buf, con->request.content_length);
38249                 ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf);
38250 @@ -271,30 +272,30 @@
38251         if (con->request.pathinfo->used) {
38252                 ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), con->request.pathinfo->ptr);
38253         }
38254 -               
38255 +
38256         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_FILENAME"), con->physical.path->ptr);
38257         ssi_env_add(p->ssi_cgi_env, CONST_STRING("DOCUMENT_ROOT"), con->physical.doc_root->ptr);
38258 -       
38259 +
38260         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_URI"), con->request.uri->ptr);
38261         ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), con->uri.query->used ? con->uri.query->ptr : "");
38262         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method));
38263         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200");
38264         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version));
38265 -       
38266 +
38267         ssi_env_add_request_headers(srv, con, p);
38268 -       
38269 +
38270         return 0;
38271  }
38272  
38273 -static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, 
38274 +static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
38275                             const char **l, size_t n) {
38276         size_t i, ssicmd = 0;
38277         char buf[255];
38278         buffer *b = NULL;
38279 -       
38280 -       struct { 
38281 +
38282 +       struct {
38283                 const char *var;
38284 -               enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD, 
38285 +               enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
38286                                 SSI_CONFIG, SSI_PRINTENV, SSI_SET, SSI_IF, SSI_ELIF,
38287                                 SSI_ELSE, SSI_ENDIF, SSI_EXEC } type;
38288         } ssicmds[] = {
38289 @@ -310,27 +311,27 @@
38290                 { "endif",    SSI_ENDIF },
38291                 { "else",     SSI_ELSE },
38292                 { "exec",     SSI_EXEC },
38293 -               
38294 +
38295                 { NULL, SSI_UNSET }
38296         };
38297 -       
38298 +
38299         for (i = 0; ssicmds[i].var; i++) {
38300                 if (0 == strcmp(l[1], ssicmds[i].var)) {
38301                         ssicmd = ssicmds[i].type;
38302                         break;
38303                 }
38304         }
38305 -       
38306 +
38307         switch(ssicmd) {
38308         case SSI_ECHO: {
38309                 /* echo */
38310                 int var = 0, enc = 0;
38311                 const char *var_val = NULL;
38312                 stat_cache_entry *sce = NULL;
38313 -               
38314 -               struct { 
38315 +
38316 +               struct {
38317                         const char *var;
38318 -                       enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI, 
38319 +                       enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
38320                                         SSI_ECHO_LAST_MODIFIED, SSI_ECHO_USER_NAME } type;
38321                 } echovars[] = {
38322                         { "DATE_GMT",      SSI_ECHO_DATE_GMT },
38323 @@ -339,27 +340,27 @@
38324                         { "DOCUMENT_URI",  SSI_ECHO_DOCUMENT_URI },
38325                         { "LAST_MODIFIED", SSI_ECHO_LAST_MODIFIED },
38326                         { "USER_NAME",     SSI_ECHO_USER_NAME },
38327 -                       
38328 +
38329                         { NULL, SSI_ECHO_UNSET }
38330                 };
38331 -               
38332 -               struct { 
38333 +
38334 +               struct {
38335                         const char *var;
38336                         enum { SSI_ENC_UNSET, SSI_ENC_URL, SSI_ENC_NONE, SSI_ENC_ENTITY } type;
38337                 } encvars[] = {
38338                         { "url",          SSI_ENC_URL },
38339                         { "none",         SSI_ENC_NONE },
38340                         { "entity",       SSI_ENC_ENTITY },
38341 -                       
38342 +
38343                         { NULL, SSI_ENC_UNSET }
38344                 };
38345 -               
38346 +
38347                 for (i = 2; i < n; i += 2) {
38348                         if (0 == strcmp(l[i], "var")) {
38349                                 int j;
38350 -                               
38351 +
38352                                 var_val = l[i+1];
38353 -                               
38354 +
38355                                 for (j = 0; echovars[j].var; j++) {
38356                                         if (0 == strcmp(l[i+1], echovars[j].var)) {
38357                                                 var = echovars[j].type;
38358 @@ -368,7 +369,7 @@
38359                                 }
38360                         } else if (0 == strcmp(l[i], "encoding")) {
38361                                 int j;
38362 -                               
38363 +
38364                                 for (j = 0; encvars[j].var; j++) {
38365                                         if (0 == strcmp(l[i+1], encvars[j].var)) {
38366                                                 enc = encvars[j].type;
38367 @@ -377,26 +378,26 @@
38368                                 }
38369                         } else {
38370                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38371 -                                               "ssi: unknow attribute for ", 
38372 +                                               "ssi: unknow attribute for ",
38373                                                 l[1], l[i]);
38374                         }
38375                 }
38376 -               
38377 +
38378                 if (p->if_is_false) break;
38379 -               
38380 +
38381                 if (!var_val) {
38382                         log_error_write(srv, __FILE__, __LINE__, "sss",
38383 -                                       "ssi: ", 
38384 +                                       "ssi: ",
38385                                         l[1], "var is missing");
38386                         break;
38387                 }
38388  
38389                 stat_cache_get_entry(srv, con, con->physical.path, &sce);
38390 -               
38391 +
38392                 switch(var) {
38393                 case SSI_ECHO_USER_NAME: {
38394                         struct passwd *pw;
38395 -                       
38396 +
38397                         b = chunkqueue_get_append_buffer(con->write_queue);
38398  #ifdef HAVE_PWD_H
38399                         if (NULL == (pw = getpwuid(sce->st.st_uid))) {
38400 @@ -411,7 +412,7 @@
38401                 }
38402                 case SSI_ECHO_LAST_MODIFIED:    {
38403                         time_t t = sce->st.st_mtime;
38404 -                       
38405 +
38406                         b = chunkqueue_get_append_buffer(con->write_queue);
38407                         if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
38408                                 buffer_copy_string(b, "(none)");
38409 @@ -422,7 +423,7 @@
38410                 }
38411                 case SSI_ECHO_DATE_LOCAL: {
38412                         time_t t = time(NULL);
38413 -                       
38414 +
38415                         b = chunkqueue_get_append_buffer(con->write_queue);
38416                         if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
38417                                 buffer_copy_string(b, "(none)");
38418 @@ -433,7 +434,7 @@
38419                 }
38420                 case SSI_ECHO_DATE_GMT: {
38421                         time_t t = time(NULL);
38422 -                       
38423 +
38424                         b = chunkqueue_get_append_buffer(con->write_queue);
38425                         if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
38426                                 buffer_copy_string(b, "(none)");
38427 @@ -444,7 +445,7 @@
38428                 }
38429                 case SSI_ECHO_DOCUMENT_NAME: {
38430                         char *sl;
38431 -                       
38432 +
38433                         b = chunkqueue_get_append_buffer(con->write_queue);
38434                         if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
38435                                 buffer_copy_string_buffer(b, con->physical.path);
38436 @@ -461,15 +462,15 @@
38437                 default: {
38438                         data_string *ds;
38439                         /* check if it is a cgi-var */
38440 -                       
38441 +
38442                         b = chunkqueue_get_append_buffer(con->write_queue);
38443 -                       
38444 +
38445                         if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) {
38446                                 buffer_copy_string_buffer(b, ds->value);
38447                         } else {
38448                                 buffer_copy_string(b, "(none)");
38449                         }
38450 -                       
38451 +
38452                         break;
38453                 }
38454                 }
38455 @@ -481,7 +482,7 @@
38456                 const char * file_path = NULL, *virt_path = NULL;
38457                 struct stat st;
38458                 char *sl;
38459 -               
38460 +
38461                 for (i = 2; i < n; i += 2) {
38462                         if (0 == strcmp(l[i], "file")) {
38463                                 file_path = l[i+1];
38464 @@ -489,28 +490,28 @@
38465                                 virt_path = l[i+1];
38466                         } else {
38467                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38468 -                                               "ssi: unknow attribute for ", 
38469 +                                               "ssi: unknow attribute for ",
38470                                                 l[1], l[i]);
38471                         }
38472                 }
38473 -               
38474 +
38475                 if (!file_path && !virt_path) {
38476                         log_error_write(srv, __FILE__, __LINE__, "sss",
38477 -                                       "ssi: ", 
38478 +                                       "ssi: ",
38479                                         l[1], "file or virtual are missing");
38480                         break;
38481                 }
38482 -               
38483 +
38484                 if (file_path && virt_path) {
38485                         log_error_write(srv, __FILE__, __LINE__, "sss",
38486 -                                       "ssi: ", 
38487 +                                       "ssi: ",
38488                                         l[1], "only one of file and virtual is allowed here");
38489                         break;
38490                 }
38491 -               
38492 -               
38493 +
38494 +
38495                 if (p->if_is_false) break;
38496 -               
38497 +
38498                 if (file_path) {
38499                         /* current doc-root */
38500                         if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
38501 @@ -519,46 +520,46 @@
38502                                 buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1);
38503                         }
38504  
38505 -                       buffer_copy_string(srv->tmp_buf, file_path); 
38506 +                       buffer_copy_string(srv->tmp_buf, file_path);
38507                         buffer_urldecode_path(srv->tmp_buf);
38508 -                       buffer_path_simplify(srv->tmp_buf, srv->tmp_buf); 
38509 -                       buffer_append_string_buffer(p->stat_fn, srv->tmp_buf); 
38510 +                       buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
38511 +                       buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
38512                 } else {
38513                         /* virtual */
38514 -                       
38515 +
38516                         if (virt_path[0] == '/') {
38517                                 buffer_copy_string(p->stat_fn, virt_path);
38518                         } else {
38519                                 /* there is always a / */
38520                                 sl = strrchr(con->uri.path->ptr, '/');
38521 -                               
38522 +
38523                                 buffer_copy_string_len(p->stat_fn, con->uri.path->ptr, sl - con->uri.path->ptr + 1);
38524                                 buffer_append_string(p->stat_fn, virt_path);
38525                         }
38526 -                       
38527 +
38528                         buffer_urldecode_path(p->stat_fn);
38529                         buffer_path_simplify(srv->tmp_buf, p->stat_fn);
38530 -                       
38531 +
38532                         /* we have an uri */
38533 -                       
38534 +
38535                         buffer_copy_string_buffer(p->stat_fn, con->physical.doc_root);
38536                         buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
38537                 }
38538 -               
38539 +
38540                 if (0 == stat(p->stat_fn->ptr, &st)) {
38541                         time_t t = st.st_mtime;
38542 -                       
38543 +
38544                         switch (ssicmd) {
38545                         case SSI_FSIZE:
38546                                 b = chunkqueue_get_append_buffer(con->write_queue);
38547                                 if (p->sizefmt) {
38548                                         int j = 0;
38549                                         const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };
38550 -                                       
38551 +
38552                                         off_t s = st.st_size;
38553 -                                       
38554 +
38555                                         for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);
38556 -                                       
38557 +
38558                                         buffer_copy_off_t(b, s);
38559                                         buffer_append_string(b, abr[j]);
38560                                 } else {
38561 @@ -579,7 +580,7 @@
38562                         }
38563                 } else {
38564                         log_error_write(srv, __FILE__, __LINE__, "sbs",
38565 -                                       "ssi: stating failed ", 
38566 +                                       "ssi: stating failed ",
38567                                         p->stat_fn, strerror(errno));
38568                 }
38569                 break;
38570 @@ -593,33 +594,33 @@
38571                                 val = l[i+1];
38572                         } else {
38573                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38574 -                                               "ssi: unknow attribute for ", 
38575 +                                               "ssi: unknow attribute for ",
38576                                                 l[1], l[i]);
38577                         }
38578                 }
38579 -               
38580 +
38581                 if (p->if_is_false) break;
38582 -               
38583 +
38584                 if (key && val) {
38585                         data_string *ds;
38586 -                       
38587 +
38588                         if (NULL == (ds = (data_string *)array_get_unused_element(p->ssi_vars, TYPE_STRING))) {
38589                                 ds = data_string_init();
38590                         }
38591                         buffer_copy_string(ds->key,   key);
38592                         buffer_copy_string(ds->value, val);
38593 -                       
38594 +
38595                         array_insert_unique(p->ssi_vars, (data_unset *)ds);
38596                 } else {
38597                         log_error_write(srv, __FILE__, __LINE__, "sss",
38598 -                                       "ssi: var and value have to be set in", 
38599 +                                       "ssi: var and value have to be set in",
38600                                         l[0], l[1]);
38601                 }
38602                 break;
38603         }
38604 -       case SSI_CONFIG: 
38605 +       case SSI_CONFIG:
38606                 if (p->if_is_false) break;
38607 -               
38608 +
38609                 for (i = 2; i < n; i += 2) {
38610                         if (0 == strcmp(l[i], "timefmt")) {
38611                                 buffer_copy_string(p->timefmt, l[i+1]);
38612 @@ -632,63 +633,65 @@
38613                                         log_error_write(srv, __FILE__, __LINE__, "sssss",
38614                                                         "ssi: unknow value for attribute '",
38615                                                         l[i],
38616 -                                                       "' for ", 
38617 +                                                       "' for ",
38618                                                         l[1], l[i+1]);
38619                                 }
38620                         } else {
38621                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38622 -                                               "ssi: unknow attribute for ", 
38623 +                                               "ssi: unknow attribute for ",
38624                                                 l[1], l[i]);
38625                         }
38626                 }
38627                 break;
38628         case SSI_PRINTENV:
38629                 if (p->if_is_false) break;
38630 -               
38631 +
38632                 b = chunkqueue_get_append_buffer(con->write_queue);
38633                 buffer_copy_string(b, "<pre>");
38634                 for (i = 0; i < p->ssi_vars->used; i++) {
38635                         data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]];
38636 -                       
38637 +
38638                         buffer_append_string_buffer(b, ds->key);
38639                         buffer_append_string(b, ": ");
38640                         buffer_append_string_buffer(b, ds->value);
38641                         buffer_append_string(b, "<br />");
38642 -                                       
38643 +
38644                 }
38645                 buffer_append_string(b, "</pre>");
38646 -               
38647 +
38648                 break;
38649         case SSI_EXEC: {
38650 +#ifndef _WIN32
38651 +
38652                 const char *cmd = NULL;
38653                 pid_t pid;
38654                 int from_exec_fds[2];
38655 -               
38656 +
38657                 for (i = 2; i < n; i += 2) {
38658                         if (0 == strcmp(l[i], "cmd")) {
38659                                 cmd = l[i+1];
38660                         } else {
38661                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38662 -                                               "ssi: unknow attribute for ", 
38663 +                                               "ssi: unknow attribute for ",
38664                                                 l[1], l[i]);
38665                         }
38666                 }
38667 -               
38668 +
38669                 if (p->if_is_false) break;
38670 -               
38671 +
38672                 /* create a return pipe and send output to the html-page
38673 -                * 
38674 -                * as exec is assumed evil it is implemented synchronously 
38675 +                *
38676 +                * as exec is assumed evil it is implemented synchronously
38677                  */
38678 -               
38679 +
38680                 if (!cmd) break;
38681 -#ifdef HAVE_FORK       
38682 +
38683                 if (pipe(from_exec_fds)) {
38684 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
38685 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
38686                                         "pipe failed: ", strerror(errno));
38687                         return -1;
38688                 }
38689 -       
38690 +
38691                 /* fork, execve */
38692                 switch (pid = fork()) {
38693                 case 0: {
38694 @@ -698,14 +701,14 @@
38695                         close(from_exec_fds[1]);
38696                         /* not needed */
38697                         close(from_exec_fds[0]);
38698 -                       
38699 +
38700                         /* close stdin */
38701                         close(STDIN_FILENO);
38702 -               
38703 +
38704                         execl("/bin/sh", "sh", "-c", cmd, NULL);
38705 -                       
38706 +
38707                         log_error_write(srv, __FILE__, __LINE__, "sss", "spawing exec failed:", strerror(errno), cmd);
38708 -               
38709 +
38710                         /* */
38711                         SEGFAULT();
38712                         break;
38713 @@ -718,9 +721,9 @@
38714                         /* father */
38715                         int status;
38716                         ssize_t r;
38717 -                       
38718 +
38719                         close(from_exec_fds[1]);
38720 -                       
38721 +
38722                         /* wait for the client to end */
38723                         if (-1 == waitpid(pid, &status, 0)) {
38724                                 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
38725 @@ -730,7 +733,7 @@
38726  
38727                                 while(1) {
38728                                         if (ioctl(from_exec_fds[0], FIONREAD, &toread)) {
38729 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
38730 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
38731                                                         "unexpected end-of-file (perhaps the ssi-exec process died)");
38732                                                 return -1;
38733                                         }
38734 @@ -738,10 +741,10 @@
38735                                         if (toread > 0) {
38736                                                 b = chunkqueue_get_append_buffer(con->write_queue);
38737  
38738 -                                               buffer_prepare_copy(b, toread + 1); 
38739 +                                               buffer_prepare_copy(b, toread + 1);
38740  
38741                                                 if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
38742 -                                                       /* read failed */ 
38743 +                                                       /* read failed */
38744                                                         break;
38745                                                 } else {
38746                                                         b->used = r;
38747 @@ -755,59 +758,58 @@
38748                                 log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally");
38749                         }
38750                         close(from_exec_fds[0]);
38751 -                       
38752 +
38753                         break;
38754                 }
38755                 }
38756  #else
38757 -
38758                 return -1;
38759  #endif
38760 -               
38761 +
38762                 break;
38763         }
38764         case SSI_IF: {
38765                 const char *expr = NULL;
38766 -               
38767 +
38768                 for (i = 2; i < n; i += 2) {
38769                         if (0 == strcmp(l[i], "expr")) {
38770                                 expr = l[i+1];
38771                         } else {
38772                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38773 -                                               "ssi: unknow attribute for ", 
38774 +                                               "ssi: unknow attribute for ",
38775                                                 l[1], l[i]);
38776                         }
38777                 }
38778 -               
38779 +
38780                 if (!expr) {
38781                         log_error_write(srv, __FILE__, __LINE__, "sss",
38782 -                                       "ssi: ", 
38783 +                                       "ssi: ",
38784                                         l[1], "expr missing");
38785                         break;
38786                 }
38787 -               
38788 +
38789                 if ((!p->if_is_false) &&
38790 -                   ((p->if_is_false_level == 0) || 
38791 +                   ((p->if_is_false_level == 0) ||
38792                      (p->if_level < p->if_is_false_level))) {
38793                         switch (ssi_eval_expr(srv, con, p, expr)) {
38794                         case -1:
38795 -                       case 0: 
38796 -                               p->if_is_false = 1; 
38797 +                       case 0:
38798 +                               p->if_is_false = 1;
38799                                 p->if_is_false_level = p->if_level;
38800                                 break;
38801 -                       case 1: 
38802 -                               p->if_is_false = 0; 
38803 +                       case 1:
38804 +                               p->if_is_false = 0;
38805                                 break;
38806                         }
38807                 }
38808 -               
38809 +
38810                 p->if_level++;
38811 -               
38812 +
38813                 break;
38814         }
38815         case SSI_ELSE:
38816                 p->if_level--;
38817 -               
38818 +
38819                 if (p->if_is_false) {
38820                         if ((p->if_level == p->if_is_false_level) &&
38821                             (p->if_is_false_endif == 0)) {
38822 @@ -815,11 +817,11 @@
38823                         }
38824                 } else {
38825                         p->if_is_false = 1;
38826 -                       
38827 +
38828                         p->if_is_false_level = p->if_level;
38829                 }
38830                 p->if_level++;
38831 -               
38832 +
38833                 break;
38834         case SSI_ELIF: {
38835                 const char *expr = NULL;
38836 @@ -828,52 +830,52 @@
38837                                 expr = l[i+1];
38838                         } else {
38839                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38840 -                                               "ssi: unknow attribute for ", 
38841 +                                               "ssi: unknow attribute for ",
38842                                                 l[1], l[i]);
38843                         }
38844                 }
38845 -               
38846 +
38847                 if (!expr) {
38848                         log_error_write(srv, __FILE__, __LINE__, "sss",
38849 -                                       "ssi: ", 
38850 +                                       "ssi: ",
38851                                         l[1], "expr missing");
38852                         break;
38853                 }
38854 -               
38855 +
38856                 p->if_level--;
38857 -               
38858 +
38859                 if (p->if_level == p->if_is_false_level) {
38860                         if ((p->if_is_false) &&
38861                             (p->if_is_false_endif == 0)) {
38862                                 switch (ssi_eval_expr(srv, con, p, expr)) {
38863                                 case -1:
38864 -                               case 0: 
38865 -                                       p->if_is_false = 1; 
38866 +                               case 0:
38867 +                                       p->if_is_false = 1;
38868                                         p->if_is_false_level = p->if_level;
38869                                         break;
38870 -                               case 1: 
38871 -                                       p->if_is_false = 0; 
38872 +                               case 1:
38873 +                                       p->if_is_false = 0;
38874                                         break;
38875                                 }
38876                         } else {
38877 -                               p->if_is_false = 1; 
38878 +                               p->if_is_false = 1;
38879                                 p->if_is_false_level = p->if_level;
38880                                 p->if_is_false_endif = 1;
38881                         }
38882                 }
38883 -               
38884 +
38885                 p->if_level++;
38886 -               
38887 +
38888                 break;
38889         }
38890         case SSI_ENDIF:
38891                 p->if_level--;
38892 -               
38893 +
38894                 if (p->if_level == p->if_is_false_level) {
38895                         p->if_is_false = 0;
38896                         p->if_is_false_endif = 0;
38897                 }
38898 -                       
38899 +
38900                 break;
38901         default:
38902                 log_error_write(srv, __FILE__, __LINE__, "ss",
38903 @@ -881,41 +883,41 @@
38904                                 l[1]);
38905                 break;
38906         }
38907 -       
38908 +
38909         return 0;
38910 -       
38911 +
38912  }
38913  
38914  static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) {
38915         stream s;
38916  #ifdef  HAVE_PCRE_H
38917         int i, n;
38918 -       
38919 +
38920  #define N 10
38921         int ovec[N * 3];
38922  #endif
38923 -       
38924 +
38925         /* get a stream to the file */
38926 -       
38927 +
38928         array_reset(p->ssi_vars);
38929         array_reset(p->ssi_cgi_env);
38930         buffer_copy_string(p->timefmt, "%a, %d %b %Y %H:%M:%S %Z");
38931         p->sizefmt = 0;
38932         build_ssi_cgi_vars(srv, con, p);
38933         p->if_is_false = 0;
38934 -       
38935 +
38936         if (-1 == stream_open(&s, con->physical.path)) {
38937                 log_error_write(srv, __FILE__, __LINE__, "sb",
38938                                 "stream-open: ", con->physical.path);
38939                 return -1;
38940         }
38941 -       
38942 -       
38943 +
38944 +
38945         /**
38946 -        * <!--#element attribute=value attribute=value ... --> 
38947 -        * 
38948 +        * <!--#element attribute=value attribute=value ... -->
38949 +        *
38950          * config       DONE
38951 -        *   errmsg     -- missing 
38952 +        *   errmsg     -- missing
38953          *   sizefmt    DONE
38954          *   timefmt    DONE
38955          * echo         DONE
38956 @@ -937,13 +939,13 @@
38957          * set          DONE
38958          *   var        DONE
38959          *   value      DONE
38960 -        * 
38961 +        *
38962          * if           DONE
38963          * elif         DONE
38964          * else         DONE
38965          * endif        DONE
38966 -        * 
38967 -        * 
38968 +        *
38969 +        *
38970          * expressions
38971          * AND, OR      DONE
38972          * comp         DONE
38973 @@ -951,118 +953,115 @@
38974          * $...         DONE
38975          * '...'        DONE
38976          * ( ... )      DONE
38977 -        * 
38978 -        * 
38979 -        * 
38980 +        *
38981 +        *
38982 +        *
38983          * ** all DONE **
38984 -        * DATE_GMT 
38985 -        *   The current date in Greenwich Mean Time. 
38986 -        * DATE_LOCAL 
38987 -        *   The current date in the local time zone. 
38988 -        * DOCUMENT_NAME 
38989 -        *   The filename (excluding directories) of the document requested by the user. 
38990 -        * DOCUMENT_URI 
38991 -        *   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. 
38992 -        * LAST_MODIFIED 
38993 -        *   The last modification date of the document requested by the user. 
38994 -        * USER_NAME 
38995 +        * DATE_GMT
38996 +        *   The current date in Greenwich Mean Time.
38997 +        * DATE_LOCAL
38998 +        *   The current date in the local time zone.
38999 +        * DOCUMENT_NAME
39000 +        *   The filename (excluding directories) of the document requested by the user.
39001 +        * DOCUMENT_URI
39002 +        *   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.
39003 +        * LAST_MODIFIED
39004 +        *   The last modification date of the document requested by the user.
39005 +        * USER_NAME
39006          *   Contains the owner of the file which included it.
39007 -        * 
39008 +        *
39009          */
39010 -#ifdef HAVE_PCRE_H     
39011 +#ifdef HAVE_PCRE_H
39012         for (i = 0; (n = pcre_exec(p->ssi_regex, NULL, s.start, s.size, i, 0, ovec, N * 3)) > 0; i = ovec[1]) {
39013                 const char **l;
39014                 /* take everything from last offset to current match pos */
39015 -               
39016 +
39017                 if (!p->if_is_false) chunkqueue_append_file(con->write_queue, con->physical.path, i, ovec[0] - i);
39018 -               
39019 +
39020                 pcre_get_substring_list(s.start, ovec, n, &l);
39021                 process_ssi_stmt(srv, con, p, l, n);
39022                 pcre_free_substring_list(l);
39023         }
39024 -       
39025 +
39026         switch(n) {
39027         case PCRE_ERROR_NOMATCH:
39028                 /* copy everything/the rest */
39029                 chunkqueue_append_file(con->write_queue, con->physical.path, i, s.size - i);
39030 -               
39031 +
39032                 break;
39033         default:
39034                 log_error_write(srv, __FILE__, __LINE__, "sd",
39035                                 "execution error while matching: ", n);
39036                 break;
39037         }
39038 -#endif 
39039 -       
39040 -       
39041 +#endif
39042 +
39043 +
39044         stream_close(&s);
39045 -       
39046 +
39047         con->file_started  = 1;
39048         con->file_finished = 1;
39049 -       
39050 +
39051         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
39052 -       
39053 +
39054         /* reset physical.path */
39055         buffer_reset(con->physical.path);
39056 -       
39057 +
39058         return 0;
39059  }
39060  
39061 -#define PATCH(x) \
39062 -       p->conf.x = s->x;
39063  static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p) {
39064         size_t i, j;
39065         plugin_config *s = p->config_storage[0];
39066 -       
39067 -       PATCH(ssi_extension);
39068 -       
39069 +
39070 +       PATCH_OPTION(ssi_extension);
39071 +
39072         /* skip the first, the global context */
39073         for (i = 1; i < srv->config_context->used; i++) {
39074                 data_config *dc = (data_config *)srv->config_context->data[i];
39075                 s = p->config_storage[i];
39076 -               
39077 +
39078                 /* condition didn't match */
39079                 if (!config_check_cond(srv, con, dc)) continue;
39080 -               
39081 +
39082                 /* merge config */
39083                 for (j = 0; j < dc->value->used; j++) {
39084                         data_unset *du = dc->value->data[j];
39085 -                       
39086 +
39087                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.extension"))) {
39088 -                               PATCH(ssi_extension);
39089 +                               PATCH_OPTION(ssi_extension);
39090                         }
39091                 }
39092         }
39093 -       
39094 +
39095         return 0;
39096  }
39097 -#undef PATCH
39098  
39099  URIHANDLER_FUNC(mod_ssi_physical_path) {
39100         plugin_data *p = p_d;
39101         size_t k;
39102 -       
39103 +
39104         if (con->physical.path->used == 0) return HANDLER_GO_ON;
39105 -       
39106 +
39107         mod_ssi_patch_connection(srv, con, p);
39108 -       
39109 +
39110         for (k = 0; k < p->conf.ssi_extension->used; k++) {
39111                 data_string *ds = (data_string *)p->conf.ssi_extension->data[k];
39112 -               
39113 +
39114                 if (ds->value->used == 0) continue;
39115 -               
39116 +
39117                 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
39118                         /* handle ssi-request */
39119 -                       
39120 +
39121                         if (mod_ssi_handle_request(srv, con, p)) {
39122                                 /* on error */
39123                                 con->http_status = 500;
39124                         }
39125 -                       
39126 +
39127                         return HANDLER_FINISHED;
39128                 }
39129         }
39130 -       
39131 +
39132         /* not found */
39133         return HANDLER_GO_ON;
39134  }
39135 @@ -1072,13 +1071,13 @@
39136  int mod_ssi_plugin_init(plugin *p) {
39137         p->version     = LIGHTTPD_VERSION_ID;
39138         p->name        = buffer_init_string("ssi");
39139 -       
39140 +
39141         p->init        = mod_ssi_init;
39142         p->handle_subrequest_start = mod_ssi_physical_path;
39143         p->set_defaults  = mod_ssi_set_defaults;
39144         p->cleanup     = mod_ssi_free;
39145 -       
39146 +
39147         p->data        = NULL;
39148 -       
39149 +
39150         return 0;
39151  }
39152 --- ../lighttpd-1.4.11/src/mod_ssi.h    2005-08-11 01:26:39.000000000 +0300
39153 +++ lighttpd-1.4.12/src/mod_ssi.h       2006-07-16 00:26:04.000000000 +0300
39154 @@ -19,23 +19,23 @@
39155  
39156  typedef struct {
39157         PLUGIN_DATA;
39158 -       
39159 -#ifdef HAVE_PCRE_H     
39160 +
39161 +#ifdef HAVE_PCRE_H
39162         pcre *ssi_regex;
39163 -#endif 
39164 +#endif
39165         buffer *timefmt;
39166         int sizefmt;
39167 -       
39168 +
39169         buffer *stat_fn;
39170 -       
39171 +
39172         array *ssi_vars;
39173         array *ssi_cgi_env;
39174 -       
39175 +
39176         int if_level, if_is_false_level, if_is_false, if_is_false_endif;
39177 -       
39178 +
39179         plugin_config **config_storage;
39180 -       
39181 -       plugin_config conf; 
39182 +
39183 +       plugin_config conf;
39184  } plugin_data;
39185  
39186  int ssi_eval_expr(server *srv, connection *con, plugin_data *p, const char *expr);
39187 --- ../lighttpd-1.4.11/src/mod_ssi_expr.c       2005-08-11 01:26:48.000000000 +0300
39188 +++ lighttpd-1.4.12/src/mod_ssi_expr.c  2006-07-16 00:26:04.000000000 +0300
39189 @@ -11,9 +11,9 @@
39190         const char *input;
39191         size_t offset;
39192         size_t size;
39193 -       
39194 +
39195         int line_pos;
39196 -       
39197 +
39198         int in_key;
39199         int in_brace;
39200         int in_cond;
39201 @@ -21,15 +21,15 @@
39202  
39203  ssi_val_t *ssi_val_init() {
39204         ssi_val_t *s;
39205 -       
39206 +
39207         s = calloc(1, sizeof(*s));
39208 -       
39209 +
39210         return s;
39211  }
39212  
39213  void ssi_val_free(ssi_val_t *s) {
39214         if (s->str) buffer_free(s->str);
39215 -       
39216 +
39217         free(s);
39218  }
39219  
39220 @@ -45,175 +45,175 @@
39221                               ssi_tokenizer_t *t, int *token_id, buffer *token) {
39222         int tid = 0;
39223         size_t i;
39224 -       
39225 +
39226         UNUSED(con);
39227  
39228         for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
39229                 char c = t->input[t->offset];
39230                 data_string *ds;
39231 -               
39232 +
39233                 switch (c) {
39234 -               case '=': 
39235 +               case '=':
39236                         tid = TK_EQ;
39237 -                       
39238 +
39239                         t->offset++;
39240                         t->line_pos++;
39241 -                       
39242 +
39243                         buffer_copy_string(token, "(=)");
39244 -                       
39245 +
39246                         break;
39247                 case '>':
39248                         if (t->input[t->offset + 1] == '=') {
39249                                 t->offset += 2;
39250                                 t->line_pos += 2;
39251 -                               
39252 +
39253                                 tid = TK_GE;
39254 -                               
39255 +
39256                                 buffer_copy_string(token, "(>=)");
39257                         } else {
39258                                 t->offset += 1;
39259                                 t->line_pos += 1;
39260 -                               
39261 +
39262                                 tid = TK_GT;
39263 -                               
39264 +
39265                                 buffer_copy_string(token, "(>)");
39266                         }
39267 -                       
39268 +
39269                         break;
39270                 case '<':
39271                         if (t->input[t->offset + 1] == '=') {
39272                                 t->offset += 2;
39273                                 t->line_pos += 2;
39274 -                               
39275 +
39276                                 tid = TK_LE;
39277 -                               
39278 +
39279                                 buffer_copy_string(token, "(<=)");
39280                         } else {
39281                                 t->offset += 1;
39282                                 t->line_pos += 1;
39283 -                               
39284 +
39285                                 tid = TK_LT;
39286 -                               
39287 +
39288                                 buffer_copy_string(token, "(<)");
39289                         }
39290 -                       
39291 +
39292                         break;
39293 -                       
39294 +
39295                 case '!':
39296                         if (t->input[t->offset + 1] == '=') {
39297                                 t->offset += 2;
39298                                 t->line_pos += 2;
39299 -                               
39300 +
39301                                 tid = TK_NE;
39302 -                               
39303 +
39304                                 buffer_copy_string(token, "(!=)");
39305                         } else {
39306                                 t->offset += 1;
39307                                 t->line_pos += 1;
39308 -                               
39309 +
39310                                 tid = TK_NOT;
39311 -                               
39312 +
39313                                 buffer_copy_string(token, "(!)");
39314                         }
39315 -                       
39316 +
39317                         break;
39318                 case '&':
39319                         if (t->input[t->offset + 1] == '&') {
39320                                 t->offset += 2;
39321                                 t->line_pos += 2;
39322 -                               
39323 +
39324                                 tid = TK_AND;
39325 -                               
39326 +
39327                                 buffer_copy_string(token, "(&&)");
39328                         } else {
39329 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
39330 -                                               "pos:", t->line_pos, 
39331 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
39332 +                                               "pos:", t->line_pos,
39333                                                 "missing second &");
39334                                 return -1;
39335                         }
39336 -                       
39337 +
39338                         break;
39339                 case '|':
39340                         if (t->input[t->offset + 1] == '|') {
39341                                 t->offset += 2;
39342                                 t->line_pos += 2;
39343 -                               
39344 +
39345                                 tid = TK_OR;
39346 -                               
39347 +
39348                                 buffer_copy_string(token, "(||)");
39349                         } else {
39350 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
39351 -                                               "pos:", t->line_pos, 
39352 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
39353 +                                               "pos:", t->line_pos,
39354                                                 "missing second |");
39355                                 return -1;
39356                         }
39357 -                       
39358 +
39359                         break;
39360                 case '\t':
39361                 case ' ':
39362                         t->offset++;
39363                         t->line_pos++;
39364                         break;
39365 -                       
39366 +
39367                 case '\'':
39368                         /* search for the terminating " */
39369                         for (i = 1; t->input[t->offset + i] && t->input[t->offset + i] != '\'';  i++);
39370 -                       
39371 +
39372                         if (t->input[t->offset + i]) {
39373                                 tid = TK_VALUE;
39374 -                               
39375 +
39376                                 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
39377 -                               
39378 +
39379                                 t->offset += i + 1;
39380                                 t->line_pos += i + 1;
39381                         } else {
39382                                 /* ERROR */
39383 -                               
39384 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
39385 -                                               "pos:", t->line_pos, 
39386 +
39387 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
39388 +                                               "pos:", t->line_pos,
39389                                                 "missing closing quote");
39390 -                               
39391 +
39392                                 return -1;
39393                         }
39394 -                       
39395 +
39396                         break;
39397                 case '(':
39398                         t->offset++;
39399                         t->in_brace++;
39400 -                               
39401 +
39402                         tid = TK_LPARAN;
39403 -                               
39404 +
39405                         buffer_copy_string(token, "(");
39406                         break;
39407                 case ')':
39408                         t->offset++;
39409                         t->in_brace--;
39410 -                               
39411 +
39412                         tid = TK_RPARAN;
39413 -                               
39414 +
39415                         buffer_copy_string(token, ")");
39416                         break;
39417                 case '$':
39418                         if (t->input[t->offset + 1] == '{') {
39419                                 for (i = 2; t->input[t->offset + i] && t->input[t->offset + i] != '}';  i++);
39420 -                               
39421 +
39422                                 if (t->input[t->offset + i] != '}') {
39423 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", 
39424 -                                                       "pos:", t->line_pos, 
39425 +                                       log_error_write(srv, __FILE__, __LINE__, "sds",
39426 +                                                       "pos:", t->line_pos,
39427                                                         "missing closing quote");
39428 -                                       
39429 +
39430                                         return -1;
39431                                 }
39432 -                               
39433 +
39434                                 buffer_copy_string_len(token, t->input + t->offset + 2, i-3);
39435                         } else {
39436                                 for (i = 1; isalpha(t->input[t->offset + i]) || t->input[t->offset + i] == '_';  i++);
39437 -                               
39438 +
39439                                 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
39440                         }
39441 -                       
39442 +
39443                         tid = TK_VALUE;
39444 -                       
39445 +
39446                         if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, token->ptr))) {
39447                                 buffer_copy_string_buffer(token, ds->value);
39448                         } else if (NULL != (ds = (data_string *)array_get_element(p->ssi_vars, token->ptr))) {
39449 @@ -221,16 +221,16 @@
39450                         } else {
39451                                 buffer_copy_string(token, "");
39452                         }
39453 -                               
39454 +
39455                         t->offset += i;
39456                         t->line_pos += i;
39457 -                       
39458 +
39459                         break;
39460                 default:
39461                         for (i = 0; isgraph(t->input[t->offset + i]);  i++) {
39462                                 char d = t->input[t->offset + i];
39463                                 switch(d) {
39464 -                               case ' ': 
39465 +                               case ' ':
39466                                 case '\t':
39467                                 case ')':
39468                                 case '(':
39469 @@ -244,25 +244,25 @@
39470                                         break;
39471                                 }
39472                         }
39473 -                       
39474 +
39475                         tid = TK_VALUE;
39476 -                               
39477 +
39478                         buffer_copy_string_len(token, t->input + t->offset, i);
39479 -                               
39480 +
39481                         t->offset += i;
39482                         t->line_pos += i;
39483 -                       
39484 +
39485                         break;
39486                 }
39487         }
39488 -                       
39489 +
39490         if (tid) {
39491                 *token_id = tid;
39492 -               
39493 +
39494                 return 1;
39495         } else if (t->offset < t->size) {
39496 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
39497 -                               "pos:", t->line_pos, 
39498 +               log_error_write(srv, __FILE__, __LINE__, "sds",
39499 +                               "pos:", t->line_pos,
39500                                 "foobar");
39501         }
39502         return 0;
39503 @@ -275,50 +275,50 @@
39504         buffer *token;
39505         ssi_ctx_t context;
39506         int ret;
39507 -       
39508 +
39509         t.input = expr;
39510         t.offset = 0;
39511         t.size = strlen(expr);
39512         t.line_pos = 1;
39513 -       
39514 +
39515         t.in_key = 1;
39516         t.in_brace = 0;
39517         t.in_cond = 0;
39518 -       
39519 +
39520         context.ok = 1;
39521         context.srv = srv;
39522 -       
39523 +
39524         /* default context */
39525 -       
39526 +
39527         pParser = ssiexprparserAlloc( malloc );
39528         token = buffer_init();
39529         while((1 == (ret = ssi_expr_tokenizer(srv, con, p, &t, &token_id, token))) && context.ok) {
39530                 ssiexprparser(pParser, token_id, token, &context);
39531 -               
39532 +
39533                 token = buffer_init();
39534         }
39535         ssiexprparser(pParser, 0, token, &context);
39536         ssiexprparserFree(pParser, free );
39537 -       
39538 +
39539         buffer_free(token);
39540 -       
39541 +
39542         if (ret == -1) {
39543 -               log_error_write(srv, __FILE__, __LINE__, "s", 
39544 +               log_error_write(srv, __FILE__, __LINE__, "s",
39545                                 "expr parser failed");
39546                 return -1;
39547         }
39548 -       
39549 +
39550         if (context.ok == 0) {
39551 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
39552 -                               "pos:", t.line_pos, 
39553 +               log_error_write(srv, __FILE__, __LINE__, "sds",
39554 +                               "pos:", t.line_pos,
39555                                 "parser failed somehow near here");
39556                 return -1;
39557         }
39558  #if 0
39559 -       log_error_write(srv, __FILE__, __LINE__, "ssd", 
39560 +       log_error_write(srv, __FILE__, __LINE__, "ssd",
39561                         "expr: ",
39562                         expr,
39563                         context.val.bo);
39564 -#endif 
39565 +#endif
39566         return context.val.bo;
39567  }
39568 --- ../lighttpd-1.4.11/src/mod_ssi_expr.h       2005-08-11 01:26:48.000000000 +0300
39569 +++ lighttpd-1.4.12/src/mod_ssi_expr.h  2006-07-16 00:26:04.000000000 +0300
39570 @@ -5,16 +5,16 @@
39571  
39572  typedef struct {
39573         enum { SSI_TYPE_UNSET, SSI_TYPE_BOOL, SSI_TYPE_STRING } type;
39574 -       
39575 +
39576         buffer *str;
39577         int     bo;
39578  } ssi_val_t;
39579  
39580  typedef struct {
39581         int     ok;
39582 -       
39583 +
39584         ssi_val_t val;
39585 -       
39586 +
39587         void   *srv;
39588  } ssi_ctx_t;
39589  
39590 --- ../lighttpd-1.4.11/src/mod_ssi_exprparser.c 2005-10-03 00:40:25.000000000 +0300
39591 +++ lighttpd-1.4.12/src/mod_ssi_exprparser.c    2006-07-17 22:02:23.000000000 +0300
39592 @@ -18,10 +18,10 @@
39593  /* Next is all token values, in a form suitable for use by makeheaders.
39594  ** This section will be null unless lemon is run with the -m switch.
39595  */
39596 -/* 
39597 +/*
39598  ** These constants (all generated automatically by the parser generator)
39599  ** specify the various kinds of tokens (terminals) that the parser
39600 -** understands. 
39601 +** understands.
39602  **
39603  ** Each symbol here is a terminal symbol in the grammar.
39604  */
39605 @@ -38,7 +38,7 @@
39606  **                       and nonterminals.  "int" is used otherwise.
39607  **    YYNOCODE           is a number of type YYCODETYPE which corresponds
39608  **                       to no legal terminal or nonterminal number.  This
39609 -**                       number is used to fill in empty slots of the hash 
39610 +**                       number is used to fill in empty slots of the hash
39611  **                       table.
39612  **    YYFALLBACK         If defined, this indicates that one or more tokens
39613  **                       have fall-back values which should be used if the
39614 @@ -47,7 +47,7 @@
39615  **                       and nonterminal numbers.  "unsigned char" is
39616  **                       used if there are fewer than 250 rules and
39617  **                       states combined.  "int" is used otherwise.
39618 -**    ssiexprparserTOKENTYPE     is the data type used for minor tokens given 
39619 +**    ssiexprparserTOKENTYPE     is the data type used for minor tokens given
39620  **                       directly to the parser from the tokenizer.
39621  **    YYMINORTYPE        is the data type used for all minor tokens.
39622  **                       This is typically a union of many types, one of
39623 @@ -91,7 +91,7 @@
39624  /* Next are that tables used to determine what action to take based on the
39625  ** current state and lookahead token.  These tables are used to implement
39626  ** functions that take a state number and lookahead value and return an
39627 -** action integer.  
39628 +** action integer.
39629  **
39630  ** Suppose the action integer is N.  Then the action is determined as
39631  ** follows
39632 @@ -116,7 +116,7 @@
39633  ** If the index value yy_shift_ofst[S]+X is out of range or if the value
39634  ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
39635  ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
39636 -** and that yy_default[S] should be used instead.  
39637 +** and that yy_default[S] should be used instead.
39638  **
39639  ** The formula above is for computing the action when the lookahead is
39640  ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
39641 @@ -168,7 +168,7 @@
39642  
39643  /* The next table maps tokens into fallback tokens.  If a construct
39644  ** like the following:
39645 -** 
39646 +**
39647  **      %fallback ID X Y Z.
39648  **
39649  ** appears in the grammer, then ID becomes a fallback token for X, Y,
39650 @@ -219,10 +219,10 @@
39651  #endif /* NDEBUG */
39652  
39653  #ifndef NDEBUG
39654 -/* 
39655 +/*
39656  ** Turn parser tracing on by giving a stream to which to write the trace
39657  ** and a prompt to preface each trace message.  Tracing is turned off
39658 -** by making either argument NULL 
39659 +** by making either argument NULL
39660  **
39661  ** Inputs:
39662  ** <ul>
39663 @@ -247,7 +247,7 @@
39664  #ifndef NDEBUG
39665  /* For tracing shifts, the names of all terminals and nonterminals
39666  ** are required.  The following table supplies these names */
39667 -static const char *yyTokenName[] = { 
39668 +static const char *yyTokenName[] = {
39669    "$",             "AND",           "OR",            "EQ",          
39670    "NE",            "GT",            "GE",            "LT",          
39671    "LE",            "NOT",           "LPARAN",        "RPARAN",      
39672 @@ -295,7 +295,7 @@
39673  #endif
39674  }
39675  
39676 -/* 
39677 +/*
39678  ** This function allocates a new parser.
39679  ** The only argument is a pointer to a function which works like
39680  ** malloc.
39681 @@ -326,7 +326,7 @@
39682      /* Here is inserted the actions which take place when a
39683      ** terminal or non-terminal is destroyed.  This can happen
39684      ** when the symbol is popped from the stack during a
39685 -    ** reduce or during error processing or when a parser is 
39686 +    ** reduce or during error processing or when a parser is
39687      ** being destroyed before it is finished parsing.
39688      **
39689      ** Note: during a reduce, the only symbols destroyed are those
39690 @@ -379,7 +379,7 @@
39691    return yymajor;
39692  }
39693  
39694 -/* 
39695 +/*
39696  ** Deallocate and destroy a parser.  Destructors are all called for
39697  ** all stack elements before shutting the parser down.
39698  **
39699 @@ -415,7 +415,7 @@
39700  ){
39701    int i;
39702    int stateno = pParser->yystack[pParser->yyidx].stateno;
39703
39704 +
39705    /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
39706    i = yy_shift_ofst[stateno];
39707    if( i==YY_SHIFT_USE_DFLT ){
39708 @@ -459,7 +459,7 @@
39709  ){
39710    int i;
39711    int stateno = pParser->yystack[pParser->yyidx].stateno;
39712
39713 +
39714    i = yy_reduce_ofst[stateno];
39715    if( i==YY_REDUCE_USE_DFLT ){
39716      return yy_default[stateno];
39717 @@ -559,7 +559,7 @@
39718    ssiexprparserARG_FETCH;
39719    yymsp = &yypParser->yystack[yypParser->yyidx];
39720  #ifndef NDEBUG
39721 -  if( yyTraceFILE && yyruleno>=0 
39722 +  if( yyTraceFILE && yyruleno>=0
39723          && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
39724      fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
39725        yyRuleName[yyruleno]);
39726 @@ -872,7 +872,7 @@
39727  #ifdef YYERRORSYMBOL
39728        /* A syntax error has occurred.
39729        ** The response to an error depends upon whether or not the
39730 -      ** grammar defines an error token "ERROR".  
39731 +      ** grammar defines an error token "ERROR".
39732        **
39733        ** This is what we do if the grammar does define ERROR:
39734        **
39735 --- ../lighttpd-1.4.11/src/mod_staticfile.c     2006-02-15 14:31:14.000000000 +0200
39736 +++ lighttpd-1.4.12/src/mod_staticfile.c        2006-07-16 00:26:03.000000000 +0300
39737 @@ -14,9 +14,11 @@
39738  #include "http_chunk.h"
39739  #include "response.h"
39740  
39741 +#include "sys-files.h"
39742 +#include "sys-strings.h"
39743  /**
39744   * this is a staticfile for a lighttpd plugin
39745 - * 
39746 + *
39747   */
39748  
39749  
39750 @@ -29,48 +31,48 @@
39751  
39752  typedef struct {
39753         PLUGIN_DATA;
39754 -       
39755 +
39756         buffer *range_buf;
39757 -       
39758 +
39759         plugin_config **config_storage;
39760 -       
39761 -       plugin_config conf; 
39762 +
39763 +       plugin_config conf;
39764  } plugin_data;
39765  
39766  /* init the plugin data */
39767  INIT_FUNC(mod_staticfile_init) {
39768         plugin_data *p;
39769 -       
39770 +
39771         p = calloc(1, sizeof(*p));
39772 -       
39773 +
39774         p->range_buf = buffer_init();
39775 -       
39776 +
39777         return p;
39778  }
39779  
39780 -/* detroy the plugin data */
39781 +/* destroy the plugin data */
39782  FREE_FUNC(mod_staticfile_free) {
39783         plugin_data *p = p_d;
39784 -       
39785 +
39786         UNUSED(srv);
39787  
39788         if (!p) return HANDLER_GO_ON;
39789 -       
39790 +
39791         if (p->config_storage) {
39792                 size_t i;
39793                 for (i = 0; i < srv->config_context->used; i++) {
39794                         plugin_config *s = p->config_storage[i];
39795 -                       
39796 +
39797                         array_free(s->exclude_ext);
39798 -                       
39799 +
39800                         free(s);
39801                 }
39802                 free(p->config_storage);
39803         }
39804         buffer_free(p->range_buf);
39805 -       
39806 +
39807         free(p);
39808 -       
39809 +
39810         return HANDLER_GO_ON;
39811  }
39812  
39813 @@ -79,63 +81,60 @@
39814  SETDEFAULTS_FUNC(mod_staticfile_set_defaults) {
39815         plugin_data *p = p_d;
39816         size_t i = 0;
39817 -       
39818 -       config_values_t cv[] = { 
39819 +
39820 +       config_values_t cv[] = {
39821                 { "static-file.exclude-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
39822                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
39823         };
39824 -       
39825 +
39826         if (!p) return HANDLER_ERROR;
39827 -       
39828 +
39829         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
39830 -       
39831 +
39832         for (i = 0; i < srv->config_context->used; i++) {
39833                 plugin_config *s;
39834 -               
39835 +
39836                 s = calloc(1, sizeof(plugin_config));
39837                 s->exclude_ext    = array_init();
39838 -               
39839 +
39840                 cv[0].destination = s->exclude_ext;
39841 -               
39842 +
39843                 p->config_storage[i] = s;
39844 -       
39845 +
39846                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
39847                         return HANDLER_ERROR;
39848                 }
39849         }
39850 -       
39851 +
39852         return HANDLER_GO_ON;
39853  }
39854  
39855 -#define PATCH(x) \
39856 -       p->conf.x = s->x;
39857  static int mod_staticfile_patch_connection(server *srv, connection *con, plugin_data *p) {
39858         size_t i, j;
39859         plugin_config *s = p->config_storage[0];
39860 -       
39861 -       PATCH(exclude_ext);
39862 -       
39863 +
39864 +       PATCH_OPTION(exclude_ext);
39865 +
39866         /* skip the first, the global context */
39867         for (i = 1; i < srv->config_context->used; i++) {
39868                 data_config *dc = (data_config *)srv->config_context->data[i];
39869                 s = p->config_storage[i];
39870 -               
39871 +
39872                 /* condition didn't match */
39873                 if (!config_check_cond(srv, con, dc)) continue;
39874 -               
39875 +
39876                 /* merge config */
39877                 for (j = 0; j < dc->value->used; j++) {
39878                         data_unset *du = dc->value->data[j];
39879 -                       
39880 +
39881                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.exclude-extensions"))) {
39882 -                               PATCH(exclude_ext);
39883 +                               PATCH_OPTION(exclude_ext);
39884                         }
39885                 }
39886         }
39887 -       
39888 +
39889         return 0;
39890  }
39891 -#undef PATCH
39892  
39893  static int http_response_parse_range(server *srv, connection *con, plugin_data *p) {
39894         int multipart = 0;
39895 @@ -146,69 +145,69 @@
39896         data_string *ds;
39897         stat_cache_entry *sce = NULL;
39898         buffer *content_type = NULL;
39899 -       
39900 +
39901         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
39902                 SEGFAULT();
39903         }
39904 -       
39905 +
39906         start = 0;
39907         end = sce->st.st_size - 1;
39908 -       
39909 +
39910         con->response.content_length = 0;
39911 -       
39912 +
39913         if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {
39914                 content_type = ds->value;
39915         }
39916 -       
39917 +
39918         for (s = con->request.http_range, error = 0;
39919              !error && *s && NULL != (minus = strchr(s, '-')); ) {
39920                 char *err;
39921                 off_t la, le;
39922 -               
39923 +
39924                 if (s == minus) {
39925                         /* -<stop> */
39926 -                       
39927 +
39928                         le = strtoll(s, &err, 10);
39929 -                       
39930 +
39931                         if (le == 0) {
39932                                 /* RFC 2616 - 14.35.1 */
39933 -                               
39934 +
39935                                 con->http_status = 416;
39936                                 error = 1;
39937                         } else if (*err == '\0') {
39938                                 /* end */
39939                                 s = err;
39940 -                               
39941 +
39942                                 end = sce->st.st_size - 1;
39943                                 start = sce->st.st_size + le;
39944                         } else if (*err == ',') {
39945                                 multipart = 1;
39946                                 s = err + 1;
39947 -                               
39948 +
39949                                 end = sce->st.st_size - 1;
39950                                 start = sce->st.st_size + le;
39951                         } else {
39952                                 error = 1;
39953                         }
39954 -                       
39955 +
39956                 } else if (*(minus+1) == '\0' || *(minus+1) == ',') {
39957                         /* <start>- */
39958 -                       
39959 +
39960                         la = strtoll(s, &err, 10);
39961 -                       
39962 +
39963                         if (err == minus) {
39964                                 /* ok */
39965 -                               
39966 +
39967                                 if (*(err + 1) == '\0') {
39968                                         s = err + 1;
39969 -                                       
39970 +
39971                                         end = sce->st.st_size - 1;
39972                                         start = la;
39973 -                                       
39974 +
39975                                 } else if (*(err + 1) == ',') {
39976                                         multipart = 1;
39977                                         s = err + 2;
39978 -                                       
39979 +
39980                                         end = sce->st.st_size - 1;
39981                                         start = la;
39982                                 } else {
39983 @@ -220,64 +219,64 @@
39984                         }
39985                 } else {
39986                         /* <start>-<stop> */
39987 -                       
39988 +
39989                         la = strtoll(s, &err, 10);
39990 -                       
39991 +
39992                         if (err == minus) {
39993                                 le = strtoll(minus+1, &err, 10);
39994 -                               
39995 +
39996                                 /* RFC 2616 - 14.35.1 */
39997                                 if (la > le) {
39998                                         error = 1;
39999                                 }
40000 -                                       
40001 +
40002                                 if (*err == '\0') {
40003                                         /* ok, end*/
40004                                         s = err;
40005 -                                       
40006 +
40007                                         end = le;
40008                                         start = la;
40009                                 } else if (*err == ',') {
40010                                         multipart = 1;
40011                                         s = err + 1;
40012 -                                       
40013 +
40014                                         end = le;
40015                                         start = la;
40016                                 } else {
40017                                         /* error */
40018 -                                       
40019 +
40020                                         error = 1;
40021                                 }
40022                         } else {
40023                                 /* error */
40024 -                               
40025 +
40026                                 error = 1;
40027                         }
40028                 }
40029 -               
40030 +
40031                 if (!error) {
40032                         if (start < 0) start = 0;
40033 -                       
40034 +
40035                         /* RFC 2616 - 14.35.1 */
40036                         if (end > sce->st.st_size - 1) end = sce->st.st_size - 1;
40037 -                       
40038 +
40039                         if (start > sce->st.st_size - 1) {
40040                                 error = 1;
40041 -                               
40042 +
40043                                 con->http_status = 416;
40044                         }
40045                 }
40046 -               
40047 +
40048                 if (!error) {
40049                         if (multipart) {
40050                                 /* write boundary-header */
40051                                 buffer *b;
40052 -                               
40053 +
40054                                 b = chunkqueue_get_append_buffer(con->write_queue);
40055 -                               
40056 +
40057                                 buffer_copy_string(b, "\r\n--");
40058                                 buffer_append_string(b, boundary);
40059 -                               
40060 +
40061                                 /* write Content-Range */
40062                                 buffer_append_string(b, "\r\nContent-Range: bytes ");
40063                                 buffer_append_off_t(b, start);
40064 @@ -285,54 +284,54 @@
40065                                 buffer_append_off_t(b, end);
40066                                 buffer_append_string(b, "/");
40067                                 buffer_append_off_t(b, sce->st.st_size);
40068 -                               
40069 +
40070                                 buffer_append_string(b, "\r\nContent-Type: ");
40071                                 buffer_append_string_buffer(b, content_type);
40072 -                               
40073 +
40074                                 /* write END-OF-HEADER */
40075                                 buffer_append_string(b, "\r\n\r\n");
40076 -                               
40077 +
40078                                 con->response.content_length += b->used - 1;
40079 -                               
40080 +
40081                         }
40082 -                       
40083 +
40084                         chunkqueue_append_file(con->write_queue, con->physical.path, start, end - start + 1);
40085                         con->response.content_length += end - start + 1;
40086                 }
40087         }
40088 -       
40089 +
40090         /* something went wrong */
40091         if (error) return -1;
40092 -       
40093 +
40094         if (multipart) {
40095                 /* add boundary end */
40096                 buffer *b;
40097 -               
40098 +
40099                 b = chunkqueue_get_append_buffer(con->write_queue);
40100 -               
40101 +
40102                 buffer_copy_string_len(b, "\r\n--", 4);
40103                 buffer_append_string(b, boundary);
40104                 buffer_append_string_len(b, "--\r\n", 4);
40105 -               
40106 +
40107                 con->response.content_length += b->used - 1;
40108 -               
40109 +
40110                 /* set header-fields */
40111 -               
40112 +
40113                 buffer_copy_string(p->range_buf, "multipart/byteranges; boundary=");
40114                 buffer_append_string(p->range_buf, boundary);
40115 -               
40116 +
40117                 /* overwrite content-type */
40118                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->range_buf));
40119         } else {
40120                 /* add Content-Range-header */
40121 -               
40122 +
40123                 buffer_copy_string(p->range_buf, "bytes ");
40124                 buffer_append_off_t(p->range_buf, start);
40125                 buffer_append_string(p->range_buf, "-");
40126                 buffer_append_off_t(p->range_buf, end);
40127                 buffer_append_string(p->range_buf, "/");
40128                 buffer_append_off_t(p->range_buf, sce->st.st_size);
40129 -               
40130 +
40131                 response_header_insert(srv, con, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(p->range_buf));
40132         }
40133  
40134 @@ -347,12 +346,12 @@
40135         stat_cache_entry *sce = NULL;
40136         buffer *mtime;
40137         data_string *ds;
40138 -       
40139 +
40140         /* someone else has done a decision for us */
40141         if (con->http_status != 0) return HANDLER_GO_ON;
40142         if (con->uri.path->used == 0) return HANDLER_GO_ON;
40143         if (con->physical.path->used == 0) return HANDLER_GO_ON;
40144 -       
40145 +
40146         /* someone else has handled this request */
40147         if (con->mode != DIRECT) return HANDLER_GO_ON;
40148  
40149 @@ -365,52 +364,52 @@
40150         default:
40151                 return HANDLER_GO_ON;
40152         }
40153 -       
40154 +
40155         mod_staticfile_patch_connection(srv, con, p);
40156 -       
40157 +
40158         s_len = con->uri.path->used - 1;
40159 -       
40160 +
40161         /* ignore certain extensions */
40162         for (k = 0; k < p->conf.exclude_ext->used; k++) {
40163 -               ds = (data_string *)p->conf.exclude_ext->data[k]; 
40164 -               
40165 +               ds = (data_string *)p->conf.exclude_ext->data[k];
40166 +
40167                 if (ds->value->used == 0) continue;
40168  
40169                 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
40170                         return HANDLER_GO_ON;
40171                 }
40172         }
40173 -       
40174 +
40175  
40176         if (con->conf.log_request_handling) {
40177                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling file as static file");
40178         }
40179 -       
40180 +
40181         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
40182                 con->http_status = 403;
40183 -               
40184 +
40185                 log_error_write(srv, __FILE__, __LINE__, "sbsb",
40186                                 "not a regular file:", con->uri.path,
40187                                 "->", con->physical.path);
40188 -               
40189 +
40190                 return HANDLER_FINISHED;
40191         }
40192 -       
40193 -       /* we only handline regular files */
40194 +
40195 +       /* we only handle regular files */
40196         if (!S_ISREG(sce->st.st_mode)) {
40197                 con->http_status = 404;
40198 -               
40199 +
40200                 if (con->conf.log_file_not_found) {
40201                         log_error_write(srv, __FILE__, __LINE__, "sbsb",
40202                                         "not a regular file:", con->uri.path,
40203                                         "->", sce->name);
40204                 }
40205 -               
40206 +
40207                 return HANDLER_FINISHED;
40208         }
40209  
40210 -       /* mod_compress might set several data directly, don't overwrite them */
40211 -       
40212 +       /* mod_compress might set several parameters directly; don't overwrite them */
40213 +
40214         /* set response content-type, if not set already */
40215  
40216         if (NULL == array_get_element(con->response.headers, "Content-Type")) {
40217 @@ -420,15 +419,15 @@
40218                         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
40219                 }
40220         }
40221 -       
40222 +
40223         if (NULL == array_get_element(con->response.headers, "ETag")) {
40224                 /* generate e-tag */
40225                 etag_mutate(con->physical.etag, sce->etag);
40226 -       
40227 +
40228                 response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
40229         }
40230         response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes"));
40231 -       
40232 +
40233         /* prepare header */
40234         if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
40235                 mtime = strftime_cache_get(srv, sce->st.st_mtime);
40236 @@ -444,34 +443,34 @@
40237                 /* check if we have a conditional GET */
40238  
40239                 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If-Range"))) {
40240 -                       /* if the value is the same as our ETag, we do a Range-request, 
40241 +                       /* if the value is the same as our ETag, we do a Range-request,
40242                          * otherwise a full 200 */
40243  
40244                         if (!buffer_is_equal(ds->value, con->physical.etag)) {
40245                                 do_range_request = 0;
40246                         }
40247                 }
40248 -       
40249 +
40250                 if (do_range_request) {
40251                         /* content prepared, I'm done */
40252                         con->file_finished = 1;
40253 -               
40254 +
40255                         if (0 == http_response_parse_range(srv, con, p)) {
40256                                 con->http_status = 206;
40257                         }
40258                         return HANDLER_FINISHED;
40259                 }
40260         }
40261 -       
40262 +
40263         /* if we are still here, prepare body */
40264 -       
40265 -       /* we add it here for all requests 
40266 -        * the HEAD request will drop it afterwards again 
40267 +
40268 +       /* we add it here for all requests
40269 +        * the HEAD request will drop it afterwards again
40270          */
40271         http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
40272 -       
40273 +
40274         con->file_finished = 1;
40275 -       
40276 +
40277         return HANDLER_FINISHED;
40278  }
40279  
40280 @@ -480,13 +479,13 @@
40281  int mod_staticfile_plugin_init(plugin *p) {
40282         p->version     = LIGHTTPD_VERSION_ID;
40283         p->name        = buffer_init_string("staticfile");
40284 -       
40285 +
40286         p->init        = mod_staticfile_init;
40287         p->handle_subrequest_start = mod_staticfile_subrequest;
40288         p->set_defaults  = mod_staticfile_set_defaults;
40289         p->cleanup     = mod_staticfile_free;
40290 -       
40291 +
40292         p->data        = NULL;
40293 -       
40294 +
40295         return 0;
40296  }
40297 --- ../lighttpd-1.4.11/src/mod_status.c 2006-01-10 21:45:32.000000000 +0200
40298 +++ lighttpd-1.4.12/src/mod_status.c    2006-07-19 20:02:55.000000000 +0300
40299 @@ -4,7 +4,6 @@
40300  #include <fcntl.h>
40301  #include <stdlib.h>
40302  #include <string.h>
40303 -#include <unistd.h>
40304  #include <errno.h>
40305  #include <time.h>
40306  #include <stdio.h>
40307 @@ -14,6 +13,7 @@
40308  #include "response.h"
40309  #include "connections.h"
40310  #include "log.h"
40311 +#include "status_counter.h"
40312  
40313  #include "plugin.h"
40314  
40315 @@ -29,114 +29,114 @@
40316  
40317  typedef struct {
40318         PLUGIN_DATA;
40319 -       
40320 +
40321         double traffic_out;
40322         double requests;
40323 -       
40324 +
40325         double mod_5s_traffic_out[5];
40326         double mod_5s_requests[5];
40327         size_t mod_5s_ndx;
40328 -       
40329 +
40330         double rel_traffic_out;
40331         double rel_requests;
40332 -       
40333 +
40334         double abs_traffic_out;
40335         double abs_requests;
40336 -       
40337 +
40338         double bytes_written;
40339 -       
40340 +
40341         buffer *module_list;
40342 -       
40343 +
40344         plugin_config **config_storage;
40345 -       
40346 -       plugin_config conf; 
40347 +
40348 +       plugin_config conf;
40349  } plugin_data;
40350  
40351  INIT_FUNC(mod_status_init) {
40352         plugin_data *p;
40353         size_t i;
40354 -       
40355 +
40356         p = calloc(1, sizeof(*p));
40357 -       
40358 +
40359         p->traffic_out = p->requests = 0;
40360         p->rel_traffic_out = p->rel_requests = 0;
40361         p->abs_traffic_out = p->abs_requests = 0;
40362         p->bytes_written = 0;
40363         p->module_list = buffer_init();
40364 -       
40365 +
40366         for (i = 0; i < 5; i++) {
40367                 p->mod_5s_traffic_out[i] = p->mod_5s_requests[i] = 0;
40368         }
40369 -       
40370 +
40371         return p;
40372  }
40373  
40374  FREE_FUNC(mod_status_free) {
40375         plugin_data *p = p_d;
40376 -       
40377 +
40378         UNUSED(srv);
40379  
40380         if (!p) return HANDLER_GO_ON;
40381 -       
40382 +
40383         buffer_free(p->module_list);
40384 -       
40385 +
40386         if (p->config_storage) {
40387                 size_t i;
40388                 for (i = 0; i < srv->config_context->used; i++) {
40389                         plugin_config *s = p->config_storage[i];
40390 -                       
40391 +
40392                         buffer_free(s->status_url);
40393                         buffer_free(s->statistics_url);
40394                         buffer_free(s->config_url);
40395 -                       
40396 +
40397                         free(s);
40398                 }
40399                 free(p->config_storage);
40400         }
40401 -       
40402 -       
40403 +
40404 +
40405         free(p);
40406 -       
40407 +
40408         return HANDLER_GO_ON;
40409  }
40410  
40411  SETDEFAULTS_FUNC(mod_status_set_defaults) {
40412         plugin_data *p = p_d;
40413         size_t i;
40414 -       
40415 -       config_values_t cv[] = { 
40416 +
40417 +       config_values_t cv[] = {
40418                 { "status.status-url",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
40419                 { "status.config-url",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
40420                 { "status.enable-sort",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
40421                 { "status.statistics-url",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
40422                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
40423         };
40424 -       
40425 +
40426         if (!p) return HANDLER_ERROR;
40427 -       
40428 +
40429         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
40430 -       
40431 +
40432         for (i = 0; i < srv->config_context->used; i++) {
40433                 plugin_config *s;
40434 -               
40435 +
40436                 s = calloc(1, sizeof(plugin_config));
40437                 s->config_url    = buffer_init();
40438                 s->status_url    = buffer_init();
40439                 s->sort          = 1;
40440                 s->statistics_url    = buffer_init();
40441 -               
40442 +
40443                 cv[0].destination = s->status_url;
40444                 cv[1].destination = s->config_url;
40445                 cv[2].destination = &(s->sort);
40446                 cv[3].destination = s->statistics_url;
40447 -               
40448 +
40449                 p->config_storage[i] = s;
40450 -       
40451 +
40452                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
40453                         return HANDLER_ERROR;
40454                 }
40455         }
40456 -       
40457 +
40458         return HANDLER_GO_ON;
40459  }
40460  
40461 @@ -151,7 +151,7 @@
40462         buffer_append_string(b, value);
40463         BUFFER_APPEND_STRING_CONST(b, "</td>\n");
40464         BUFFER_APPEND_STRING_CONST(b, "   </tr>\n");
40465 -       
40466 +
40467         return 0;
40468  }
40469  
40470 @@ -161,13 +161,13 @@
40471         buffer_append_string(b, key);
40472         BUFFER_APPEND_STRING_CONST(b, "</th>\n");
40473         BUFFER_APPEND_STRING_CONST(b, "   </tr>\n");
40474 -       
40475 +
40476         return 0;
40477  }
40478  
40479  static int mod_status_header_append_sort(buffer *b, void *p_d, const char* key) {
40480         plugin_data *p = p_d;
40481 -       
40482 +
40483         if (p->conf.sort) {
40484                 BUFFER_APPEND_STRING_CONST(b, "<th class=\"status\"><a href=\"#\" class=\"sortheader\" onclick=\"resort(this);return false;\">");
40485                 buffer_append_string(b, key);
40486 @@ -177,13 +177,13 @@
40487                 buffer_append_string(b, key);
40488                 BUFFER_APPEND_STRING_CONST(b, "</th>\n");
40489         }
40490 -       
40491 +
40492         return 0;
40493  }
40494  
40495  static int mod_status_get_multiplier(double *avg, char *multiplier, int size) {
40496         *multiplier = ' ';
40497 -       
40498 +
40499         if (*avg > size) { *avg /= size; *multiplier = 'k'; }
40500         if (*avg > size) { *avg /= size; *multiplier = 'M'; }
40501         if (*avg > size) { *avg /= size; *multiplier = 'G'; }
40502 @@ -202,21 +202,21 @@
40503         size_t j;
40504         double avg;
40505         char multiplier = '\0';
40506 -       char buf[32];
40507 +       char buf[128];
40508         time_t ts;
40509 -       
40510 +
40511         int days, hours, mins, seconds;
40512 -       
40513 +
40514         b = chunkqueue_get_append_buffer(con->write_queue);
40515  
40516 -       BUFFER_COPY_STRING_CONST(b, 
40517 +       BUFFER_COPY_STRING_CONST(b,
40518                                  "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
40519                                  "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
40520                                  "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
40521                                  "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
40522                                  " <head>\n"
40523                                  "  <title>Status</title>\n");
40524 -       
40525 +
40526         BUFFER_APPEND_STRING_CONST(b,
40527                                    "  <style type=\"text/css\">\n"
40528                                    "    table.status { border: black solid thin; }\n"
40529 @@ -226,14 +226,14 @@
40530                                    "    a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n"
40531                                    "    span.sortarrow { color: white; text-decoration: none; }\n"
40532                                    "  </style>\n");
40533 -       
40534 +
40535         if (p->conf.sort) {
40536                 BUFFER_APPEND_STRING_CONST(b,
40537                                            "<script type=\"text/javascript\">\n"
40538                                            "// <!--\n"
40539                                            "var sort_column;\n"
40540                                            "var prev_span = null;\n");
40541 -               
40542 +
40543                 BUFFER_APPEND_STRING_CONST(b,
40544                                            "function get_inner_text(el) {\n"
40545                                            " if((typeof el == 'string')||(typeof el == 'undefined'))\n"
40546 @@ -251,7 +251,7 @@
40547                                            " }\n"
40548                                            " return str;\n"
40549                                            "}\n");
40550 -               
40551 +
40552                 BUFFER_APPEND_STRING_CONST(b,
40553                                            "function sortfn(a,b) {\n"
40554                                            " var at = get_inner_text(a.cells[sort_column]);\n"
40555 @@ -266,7 +266,7 @@
40556                                            "  else return 1;\n"
40557                                            " }\n"
40558                                            "}\n");
40559 -               
40560 +
40561                 BUFFER_APPEND_STRING_CONST(b,
40562                                            "function resort(lnk) {\n"
40563                                            " var span = lnk.childNodes[1];\n"
40564 @@ -276,7 +276,7 @@
40565                                            "  rows[j-1] = table.rows[j];\n"
40566                                            " sort_column = lnk.parentNode.cellIndex;\n"
40567                                            " rows.sort(sortfn);\n");
40568 -               
40569 +
40570                 BUFFER_APPEND_STRING_CONST(b,
40571                                            " if (prev_span != null) prev_span.innerHTML = '';\n"
40572                                            " if (span.getAttribute('sortdir')=='down') {\n"
40573 @@ -294,175 +294,175 @@
40574                                            "// -->\n"
40575                                            "</script>\n");
40576         }
40577 -       
40578 -       BUFFER_APPEND_STRING_CONST(b, 
40579 +
40580 +       BUFFER_APPEND_STRING_CONST(b,
40581                                  " </head>\n"
40582                                  " <body>\n");
40583 -       
40584 -       
40585 -       
40586 +
40587 +
40588 +
40589         /* connection listing */
40590         BUFFER_APPEND_STRING_CONST(b, "<h1>Server-Status</h1>");
40591 -       
40592 -       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">");
40593 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\">");
40594 +
40595 +       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" id=\"status\" summary=\"Server Status\">");
40596 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\"><span id=\"host_addr\">");
40597         buffer_append_string_buffer(b, con->uri.authority);
40598 -       BUFFER_APPEND_STRING_CONST(b, " (");
40599 +       BUFFER_APPEND_STRING_CONST(b, "</span> (<span id=\"host_name\">");
40600         buffer_append_string_buffer(b, con->server_name);
40601 -       BUFFER_APPEND_STRING_CONST(b, ")</td></tr>\n");
40602 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\">");
40603 -       
40604 +       BUFFER_APPEND_STRING_CONST(b, "</span>)</td></tr>\n");
40605 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\" id=\"uptime\">");
40606 +
40607         ts = srv->cur_ts - srv->startup_ts;
40608 -       
40609 +
40610         days = ts / (60 * 60 * 24);
40611         ts %= (60 * 60 * 24);
40612 -       
40613 +
40614         hours = ts / (60 * 60);
40615         ts %= (60 * 60);
40616 -       
40617 +
40618         mins = ts / (60);
40619         ts %= (60);
40620 -       
40621 +
40622         seconds = ts;
40623 -       
40624 +
40625         if (days) {
40626                 buffer_append_long(b, days);
40627                 BUFFER_APPEND_STRING_CONST(b, " days ");
40628         }
40629 -       
40630 +
40631         if (hours) {
40632                 buffer_append_long(b, hours);
40633                 BUFFER_APPEND_STRING_CONST(b, " hours ");
40634         }
40635 -       
40636 +
40637         if (mins) {
40638                 buffer_append_long(b, mins);
40639                 BUFFER_APPEND_STRING_CONST(b, " min ");
40640         }
40641 -       
40642 +
40643         buffer_append_long(b, seconds);
40644         BUFFER_APPEND_STRING_CONST(b, " s");
40645 -       
40646 +
40647         BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40648         BUFFER_APPEND_STRING_CONST(b, "<tr><td>Started at</td><td class=\"string\">");
40649 -       
40650 +
40651         ts = srv->startup_ts;
40652 -       
40653 -       strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts));
40654 +
40655 +       strftime(buf, sizeof(buf) - 1, "<span id=\"start_date\">%Y-%m-%d</span> <span id=\"start_time\">%H:%M:%S</span>", localtime(&ts));
40656         buffer_append_string(b, buf);
40657         BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40658 -       
40659 -       
40660 +
40661 +
40662         BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">absolute (since start)</th></tr>\n");
40663 -       
40664 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40665 +
40666 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\" ><span id=\"requests\">");
40667         avg = p->abs_requests;
40668  
40669         mod_status_get_multiplier(&avg, &multiplier, 1000);
40670 -       
40671 +
40672         buffer_append_long(b, avg);
40673 -       BUFFER_APPEND_STRING_CONST(b, " ");
40674 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_mult\">");
40675         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40676 -       BUFFER_APPEND_STRING_CONST(b, "req</td></tr>\n");
40677 -       
40678 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40679 +       BUFFER_APPEND_STRING_CONST(b, "</span>req</td></tr>\n");
40680 +
40681 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic\">");
40682         avg = p->abs_traffic_out;
40683  
40684         mod_status_get_multiplier(&avg, &multiplier, 1024);
40685  
40686         sprintf(buf, "%.2f", avg);
40687         buffer_append_string(b, buf);
40688 -       BUFFER_APPEND_STRING_CONST(b, " ");
40689 +       BUFFER_APPEND_STRING_CONST(b, "</span>  <span id=\"traffic_mult\">");
40690         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40691 -       BUFFER_APPEND_STRING_CONST(b, "byte</td></tr>\n");
40692 +       BUFFER_APPEND_STRING_CONST(b, "</span>byte</td></tr>\n");
40693  
40694  
40695  
40696         BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (since start)</th></tr>\n");
40697 -       
40698 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40699 +
40700 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_avg\">");
40701         avg = p->abs_requests / (srv->cur_ts - srv->startup_ts);
40702  
40703         mod_status_get_multiplier(&avg, &multiplier, 1000);
40704  
40705         buffer_append_long(b, avg);
40706 -       BUFFER_APPEND_STRING_CONST(b, " ");
40707 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_avg_mult\">");
40708         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40709 -       BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
40710 -       
40711 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40712 +       BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
40713 +
40714 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic_avg\">");
40715         avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts);
40716  
40717         mod_status_get_multiplier(&avg, &multiplier, 1024);
40718  
40719         sprintf(buf, "%.2f", avg);
40720         buffer_append_string(b, buf);
40721 -       BUFFER_APPEND_STRING_CONST(b, " ");
40722 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"traffic_avg_mult\">");
40723         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40724 -       BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
40725 +       BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
40726 +
40727 +
40728  
40729 -       
40730 -       
40731         BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n");
40732         for (j = 0, avg = 0; j < 5; j++) {
40733                 avg += p->mod_5s_requests[j];
40734         }
40735 -       
40736 +
40737         avg /= 5;
40738 -       
40739 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40740 +
40741 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_sliding_avg\">");
40742  
40743         mod_status_get_multiplier(&avg, &multiplier, 1000);
40744  
40745         buffer_append_long(b, avg);
40746 -       BUFFER_APPEND_STRING_CONST(b, " ");
40747 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_avg_mult\">");
40748         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40749 -       
40750 -       BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
40751 -       
40752 +
40753 +       BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
40754 +
40755         for (j = 0, avg = 0; j < 5; j++) {
40756                 avg += p->mod_5s_traffic_out[j];
40757         }
40758 -       
40759 +
40760         avg /= 5;
40761 -       
40762 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40763 +
40764 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"requests_sliding_traffic\">");
40765  
40766         mod_status_get_multiplier(&avg, &multiplier, 1024);
40767  
40768         sprintf(buf, "%.2f", avg);
40769         buffer_append_string(b, buf);
40770 -       BUFFER_APPEND_STRING_CONST(b, " ");
40771 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_traffic_mult\">");
40772         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40773 -       BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
40774 -       
40775 +       BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
40776 +
40777         BUFFER_APPEND_STRING_CONST(b, "</table>\n");
40778 -       
40779 -       
40780 +
40781 +
40782         BUFFER_APPEND_STRING_CONST(b, "<hr />\n<pre><b>legend</b>\n");
40783         BUFFER_APPEND_STRING_CONST(b, ". = connect, C = close, E = hard error\n");
40784         BUFFER_APPEND_STRING_CONST(b, "r = read, R = read-POST, W = write, h = handle-request\n");
40785         BUFFER_APPEND_STRING_CONST(b, "q = request-start,  Q = request-end\n");
40786         BUFFER_APPEND_STRING_CONST(b, "s = response-start, S = response-end\n");
40787 -       
40788 -       BUFFER_APPEND_STRING_CONST(b, "<b>");
40789 +
40790 +       BUFFER_APPEND_STRING_CONST(b, "<strong><span id=\"connections\">");
40791         buffer_append_long(b, srv->conns->used);
40792 -       BUFFER_APPEND_STRING_CONST(b, " connections</b>\n");
40793 -       
40794 +       BUFFER_APPEND_STRING_CONST(b, "</span> connections</strong>\n");
40795 +
40796         for (j = 0; j < srv->conns->used; j++) {
40797                 connection *c = srv->conns->ptr[j];
40798                 const char *state = connection_get_short_state(c->state);
40799 -               
40800 +
40801                 buffer_append_string_len(b, state, 1);
40802 -               
40803 +
40804                 if (((j + 1) % 50) == 0) {
40805                         BUFFER_APPEND_STRING_CONST(b, "\n");
40806                 }
40807         }
40808 -       
40809 +
40810         BUFFER_APPEND_STRING_CONST(b, "\n</pre><hr />\n<h2>Connections</h2>\n");
40811 -       
40812 -       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">\n");
40813 +
40814 +       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" summary=\"Current connections\" id=\"clients\">\n");
40815         BUFFER_APPEND_STRING_CONST(b, "<tr>");
40816         mod_status_header_append_sort(b, p_d, "Client IP");
40817         mod_status_header_append_sort(b, p_d, "Read");
40818 @@ -473,16 +473,16 @@
40819         mod_status_header_append_sort(b, p_d, "URI");
40820         mod_status_header_append_sort(b, p_d, "File");
40821         BUFFER_APPEND_STRING_CONST(b, "</tr>\n");
40822 -       
40823 +
40824         for (j = 0; j < srv->conns->used; j++) {
40825                 connection *c = srv->conns->ptr[j];
40826 -               
40827 -               BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string\">");
40828 -               
40829 +
40830 +               BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string ip\">");
40831 +
40832                 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr)));
40833 -               
40834 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40835 -               
40836 +
40837 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_read\">");
40838 +
40839                 if (con->request.content_length) {
40840                         buffer_append_long(b, c->request_content_queue->bytes_in);
40841                         BUFFER_APPEND_STRING_CONST(b, "/");
40842 @@ -490,55 +490,55 @@
40843                 } else {
40844                         BUFFER_APPEND_STRING_CONST(b, "0/0");
40845                 }
40846 -       
40847 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40848 -               
40849 +
40850 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_written\">");
40851 +
40852                 buffer_append_off_t(b, chunkqueue_written(c->write_queue));
40853                 BUFFER_APPEND_STRING_CONST(b, "/");
40854                 buffer_append_off_t(b, chunkqueue_length(c->write_queue));
40855 -               
40856 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40857 -               
40858 +
40859 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string state\">");
40860 +
40861                 buffer_append_string(b, connection_get_state(c->state));
40862 -               
40863 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40864 -               
40865 +
40866 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int time\">");
40867 +
40868                 buffer_append_long(b, srv->cur_ts - c->request_start);
40869 -               
40870 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40871 -               
40872 +
40873 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string host\">");
40874 +
40875                 if (buffer_is_empty(c->server_name)) {
40876                         buffer_append_string_buffer(b, c->uri.authority);
40877                 }
40878                 else {
40879                         buffer_append_string_buffer(b, c->server_name);
40880                 }
40881 -               
40882 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40883 -               
40884 +
40885 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string uri\">");
40886 +
40887                 if (!buffer_is_empty(c->uri.path)) {
40888                         buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML);
40889                 }
40890 -               
40891 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40892 -               
40893 +
40894 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string file\">");
40895 +
40896                 buffer_append_string_buffer(b, c->physical.path);
40897 -               
40898 +
40899                 BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40900         }
40901 -       
40902 -       
40903 -       BUFFER_APPEND_STRING_CONST(b, 
40904 +
40905 +
40906 +       BUFFER_APPEND_STRING_CONST(b,
40907                       "</table>\n");
40908 -       
40909 -       
40910 -       BUFFER_APPEND_STRING_CONST(b, 
40911 +
40912 +
40913 +       BUFFER_APPEND_STRING_CONST(b,
40914                       " </body>\n"
40915                       "</html>\n"
40916                       );
40917 -       
40918 +
40919         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
40920 -       
40921 +
40922         return 0;
40923  }
40924  
40925 @@ -548,7 +548,7 @@
40926         buffer *b;
40927         double avg;
40928         time_t ts;
40929 -       
40930 +
40931         b = chunkqueue_get_append_buffer(con->write_queue);
40932  
40933         /* output total number of requests */
40934 @@ -556,19 +556,19 @@
40935         avg = p->abs_requests;
40936         buffer_append_long(b, avg);
40937         BUFFER_APPEND_STRING_CONST(b, "\n");
40938 -       
40939 +
40940         /* output total traffic out in kbytes */
40941         BUFFER_APPEND_STRING_CONST(b, "Total kBytes: ");
40942         avg = p->abs_traffic_out / 1024;
40943         buffer_append_long(b, avg);
40944         BUFFER_APPEND_STRING_CONST(b, "\n");
40945 -       
40946 +
40947         /* output uptime */
40948         BUFFER_APPEND_STRING_CONST(b, "Uptime: ");
40949         ts = srv->cur_ts - srv->startup_ts;
40950         buffer_append_long(b, ts);
40951         BUFFER_APPEND_STRING_CONST(b, "\n");
40952 -       
40953 +
40954         /* output busy servers */
40955         BUFFER_APPEND_STRING_CONST(b, "BusyServers: ");
40956         buffer_append_long(b, srv->conns->used);
40957 @@ -577,7 +577,7 @@
40958         /* set text/plain output */
40959  
40960         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
40961 -       
40962 +
40963         return 0;
40964  }
40965  
40966 @@ -585,16 +585,16 @@
40967         plugin_data *p = p_d;
40968         buffer *b, *m = p->module_list;
40969         size_t i;
40970 -       array *st = srv->status;
40971 +       array *st = status_counter_get_array();
40972  
40973         if (0 == st->used) {
40974                 /* we have nothing to send */
40975                 con->http_status = 204;
40976                 con->file_finished = 1;
40977 -       
40978 +
40979                 return HANDLER_FINISHED;
40980         }
40981 -       
40982 +
40983         b = chunkqueue_get_append_buffer(con->write_queue);
40984  
40985         for (i = 0; i < st->used; i++) {
40986 @@ -605,27 +605,27 @@
40987                 buffer_append_long(b, ((data_integer *)(st->data[ndx]))->value);
40988                 buffer_append_string(b, "\n");
40989         }
40990 -       
40991 +
40992         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
40993 -       
40994 +
40995         con->http_status = 200;
40996         con->file_finished = 1;
40997 -       
40998 +
40999         return HANDLER_FINISHED;
41000  }
41001  
41002  
41003  static handler_t mod_status_handle_server_status(server *srv, connection *con, void *p_d) {
41004 -       
41005 +
41006         if (buffer_is_equal_string(con->uri.query, CONST_STR_LEN("auto"))) {
41007                 mod_status_handle_server_status_text(srv, con, p_d);
41008         } else {
41009                 mod_status_handle_server_status_html(srv, con, p_d);
41010         }
41011 -       
41012 +
41013         con->http_status = 200;
41014         con->file_finished = 1;
41015 -       
41016 +
41017         return HANDLER_FINISHED;
41018  }
41019  
41020 @@ -634,9 +634,9 @@
41021         plugin_data *p = p_d;
41022         buffer *b, *m = p->module_list;
41023         size_t i;
41024 -       
41025 -       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] = 
41026 -       { 
41027 +
41028 +       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
41029 +       {
41030                 /* - poll is most reliable
41031                  * - select works everywhere
41032                  * - linux-* are experimental
41033 @@ -661,10 +661,10 @@
41034  #endif
41035                 { FDEVENT_HANDLER_UNSET,          NULL }
41036         };
41037 -       
41038 +
41039         b = chunkqueue_get_append_buffer(con->write_queue);
41040 -       
41041 -       BUFFER_COPY_STRING_CONST(b, 
41042 +
41043 +       BUFFER_COPY_STRING_CONST(b,
41044                            "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
41045                            "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
41046                            "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
41047 @@ -675,7 +675,7 @@
41048                            " <body>\n"
41049                            "  <h1>" PACKAGE_NAME " " PACKAGE_VERSION "</h1>\n"
41050                            "  <table border=\"1\">\n");
41051 -       
41052 +
41053         mod_status_header_append(b, "Server-Features");
41054  #ifdef HAVE_PCRE_H
41055         mod_status_row_append(b, "RegEx Conditionals", "enabled");
41056 @@ -683,21 +683,21 @@
41057         mod_status_row_append(b, "RegEx Conditionals", "disabled - pcre missing");
41058  #endif
41059         mod_status_header_append(b, "Network Engine");
41060 -       
41061 +
41062         for (i = 0; event_handlers[i].name; i++) {
41063                 if (event_handlers[i].et == srv->event_handler) {
41064                         mod_status_row_append(b, "fd-Event-Handler", event_handlers[i].name);
41065                         break;
41066                 }
41067         }
41068 -       
41069 +
41070         mod_status_header_append(b, "Config-File-Settings");
41071 -       
41072 +
41073         for (i = 0; i < srv->plugins.used; i++) {
41074                 plugin **ps = srv->plugins.ptr;
41075 -               
41076 +
41077                 plugin *pl = ps[i];
41078 -       
41079 +
41080                 if (i == 0) {
41081                         buffer_copy_string_buffer(m, pl->name);
41082                 } else {
41083 @@ -705,137 +705,135 @@
41084                         buffer_append_string_buffer(m, pl->name);
41085                 }
41086         }
41087 -       
41088 +
41089         mod_status_row_append(b, "Loaded Modules", m->ptr);
41090 -       
41091 +
41092         BUFFER_APPEND_STRING_CONST(b, "  </table>\n");
41093 -       
41094 -       BUFFER_APPEND_STRING_CONST(b, 
41095 +
41096 +       BUFFER_APPEND_STRING_CONST(b,
41097                       " </body>\n"
41098                       "</html>\n"
41099                       );
41100 -       
41101 +
41102         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
41103 -       
41104 +
41105         con->http_status = 200;
41106         con->file_finished = 1;
41107 -       
41108 +
41109         return HANDLER_FINISHED;
41110  }
41111  
41112 -#define PATCH(x) \
41113 -       p->conf.x = s->x;
41114  static int mod_status_patch_connection(server *srv, connection *con, plugin_data *p) {
41115         size_t i, j;
41116         plugin_config *s = p->config_storage[0];
41117 -       
41118 -       PATCH(status_url);
41119 -       PATCH(config_url);
41120 -       PATCH(sort);
41121 -       PATCH(statistics_url);
41122 -       
41123 +
41124 +       PATCH_OPTION(status_url);
41125 +       PATCH_OPTION(config_url);
41126 +       PATCH_OPTION(sort);
41127 +       PATCH_OPTION(statistics_url);
41128 +
41129         /* skip the first, the global context */
41130         for (i = 1; i < srv->config_context->used; i++) {
41131                 data_config *dc = (data_config *)srv->config_context->data[i];
41132                 s = p->config_storage[i];
41133 -               
41134 +
41135                 /* condition didn't match */
41136                 if (!config_check_cond(srv, con, dc)) continue;
41137 -               
41138 +
41139                 /* merge config */
41140                 for (j = 0; j < dc->value->used; j++) {
41141                         data_unset *du = dc->value->data[j];
41142 -                       
41143 +
41144                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.status-url"))) {
41145 -                               PATCH(status_url);
41146 +                               PATCH_OPTION(status_url);
41147                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.config-url"))) {
41148 -                               PATCH(config_url);
41149 +                               PATCH_OPTION(config_url);
41150                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.enable-sort"))) {
41151 -                               PATCH(sort);
41152 +                               PATCH_OPTION(sort);
41153                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.statistics-url"))) {
41154 -                               PATCH(statistics_url);
41155 -                       } 
41156 +                               PATCH_OPTION(statistics_url);
41157 +                       }
41158                 }
41159         }
41160 -       
41161 +
41162         return 0;
41163  }
41164  
41165  static handler_t mod_status_handler(server *srv, connection *con, void *p_d) {
41166         plugin_data *p = p_d;
41167 -       
41168 +
41169         mod_status_patch_connection(srv, con, p);
41170 -       
41171 -       if (!buffer_is_empty(p->conf.status_url) && 
41172 +
41173 +       if (!buffer_is_empty(p->conf.status_url) &&
41174             buffer_is_equal(p->conf.status_url, con->uri.path)) {
41175                 return mod_status_handle_server_status(srv, con, p_d);
41176 -       } else if (!buffer_is_empty(p->conf.config_url) && 
41177 +       } else if (!buffer_is_empty(p->conf.config_url) &&
41178             buffer_is_equal(p->conf.config_url, con->uri.path)) {
41179                 return mod_status_handle_server_config(srv, con, p_d);
41180 -       } else if (!buffer_is_empty(p->conf.statistics_url) && 
41181 +       } else if (!buffer_is_empty(p->conf.statistics_url) &&
41182             buffer_is_equal(p->conf.statistics_url, con->uri.path)) {
41183                 return mod_status_handle_server_statistics(srv, con, p_d);
41184         }
41185 -       
41186 +
41187         return HANDLER_GO_ON;
41188  }
41189  
41190  TRIGGER_FUNC(mod_status_trigger) {
41191         plugin_data *p = p_d;
41192         size_t i;
41193 -       
41194 +
41195         /* check all connections */
41196         for (i = 0; i < srv->conns->used; i++) {
41197                 connection *c = srv->conns->ptr[i];
41198 -               
41199 +
41200                 p->bytes_written += c->bytes_written_cur_second;
41201         }
41202 -       
41203 +
41204         /* a sliding average */
41205         p->mod_5s_traffic_out[p->mod_5s_ndx] = p->bytes_written;
41206         p->mod_5s_requests   [p->mod_5s_ndx] = p->requests;
41207 -       
41208 +
41209         p->mod_5s_ndx = (p->mod_5s_ndx+1) % 5;
41210 -       
41211 +
41212         p->abs_traffic_out += p->bytes_written;
41213         p->rel_traffic_out += p->bytes_written;
41214 -       
41215 +
41216         p->bytes_written = 0;
41217 -       
41218 +
41219         /* reset storage - second */
41220         p->traffic_out = 0;
41221         p->requests    = 0;
41222 -       
41223 +
41224         return HANDLER_GO_ON;
41225  }
41226  
41227  REQUESTDONE_FUNC(mod_status_account) {
41228         plugin_data *p = p_d;
41229 -       
41230 +
41231         UNUSED(srv);
41232  
41233         p->requests++;
41234         p->rel_requests++;
41235         p->abs_requests++;
41236 -       
41237 +
41238         p->bytes_written += con->bytes_written_cur_second;
41239 -       
41240 +
41241         return HANDLER_GO_ON;
41242  }
41243  
41244  int mod_status_plugin_init(plugin *p) {
41245         p->version     = LIGHTTPD_VERSION_ID;
41246         p->name        = buffer_init_string("status");
41247 -       
41248 +
41249         p->init        = mod_status_init;
41250         p->cleanup     = mod_status_free;
41251         p->set_defaults= mod_status_set_defaults;
41252 -       
41253 +
41254         p->handle_uri_clean    = mod_status_handler;
41255         p->handle_trigger      = mod_status_trigger;
41256         p->handle_request_done = mod_status_account;
41257 -       
41258 +
41259         p->data        = NULL;
41260 -       
41261 +
41262         return 0;
41263  }
41264 --- ../lighttpd-1.4.11/src/mod_trigger_b4_dl.c  2005-09-23 22:53:55.000000000 +0300
41265 +++ lighttpd-1.4.12/src/mod_trigger_b4_dl.c     2006-07-16 00:26:03.000000000 +0300
41266 @@ -24,18 +24,18 @@
41267  
41268  /**
41269   * this is a trigger_b4_dl for a lighttpd plugin
41270 - * 
41271 + *
41272   */
41273  
41274  /* plugin config for all request/connections */
41275  
41276  typedef struct {
41277         buffer *db_filename;
41278 -       
41279 +
41280         buffer *trigger_url;
41281         buffer *download_url;
41282         buffer *deny_url;
41283 -       
41284 +
41285         array  *mc_hosts;
41286         buffer *mc_namespace;
41287  #if defined(HAVE_PCRE_H)
41288 @@ -46,58 +46,58 @@
41289         GDBM_FILE db;
41290  #endif
41291  
41292 -#if defined(HAVE_MEMCACHE_H) 
41293 +#if defined(HAVE_MEMCACHE_H)
41294         struct memcache *mc;
41295  #endif
41296 -       
41297 +
41298         unsigned short trigger_timeout;
41299         unsigned short debug;
41300  } plugin_config;
41301  
41302  typedef struct {
41303         PLUGIN_DATA;
41304 -       
41305 +
41306         buffer *tmp_buf;
41307 -       
41308 +
41309         plugin_config **config_storage;
41310 -       
41311 -       plugin_config conf; 
41312 +
41313 +       plugin_config conf;
41314  } plugin_data;
41315  
41316  /* init the plugin data */
41317  INIT_FUNC(mod_trigger_b4_dl_init) {
41318         plugin_data *p;
41319 -       
41320 +
41321         p = calloc(1, sizeof(*p));
41322 -       
41323 +
41324         p->tmp_buf = buffer_init();
41325 -       
41326 +
41327         return p;
41328  }
41329  
41330  /* detroy the plugin data */
41331  FREE_FUNC(mod_trigger_b4_dl_free) {
41332         plugin_data *p = p_d;
41333 -       
41334 +
41335         UNUSED(srv);
41336  
41337         if (!p) return HANDLER_GO_ON;
41338 -       
41339 +
41340         if (p->config_storage) {
41341                 size_t i;
41342                 for (i = 0; i < srv->config_context->used; i++) {
41343                         plugin_config *s = p->config_storage[i];
41344  
41345                         if (!s) continue;
41346 -                       
41347 +
41348                         buffer_free(s->db_filename);
41349                         buffer_free(s->download_url);
41350                         buffer_free(s->trigger_url);
41351                         buffer_free(s->deny_url);
41352 -                       
41353 +
41354                         buffer_free(s->mc_namespace);
41355                         array_free(s->mc_hosts);
41356 -                       
41357 +
41358  #if defined(HAVE_PCRE_H)
41359                         if (s->trigger_regex) pcre_free(s->trigger_regex);
41360                         if (s->download_regex) pcre_free(s->download_regex);
41361 @@ -108,16 +108,16 @@
41362  #if defined(HAVE_MEMCACHE_H)
41363                         if (s->mc) mc_free(s->mc);
41364  #endif
41365 -                       
41366 +
41367                         free(s);
41368                 }
41369                 free(p->config_storage);
41370         }
41371 -       
41372 +
41373         buffer_free(p->tmp_buf);
41374 -       
41375 +
41376         free(p);
41377 -       
41378 +
41379         return HANDLER_GO_ON;
41380  }
41381  
41382 @@ -126,9 +126,9 @@
41383  SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
41384         plugin_data *p = p_d;
41385         size_t i = 0;
41386 -       
41387 -       
41388 -       config_values_t cv[] = { 
41389 +
41390 +
41391 +       config_values_t cv[] = {
41392                 { "trigger-before-download.gdbm-filename",   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
41393                 { "trigger-before-download.trigger-url",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
41394                 { "trigger-before-download.download-url",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
41395 @@ -139,18 +139,18 @@
41396                 { "trigger-before-download.debug",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 7 */
41397                 { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
41398         };
41399 -       
41400 +
41401         if (!p) return HANDLER_ERROR;
41402 -       
41403 +
41404         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
41405 -       
41406 +
41407         for (i = 0; i < srv->config_context->used; i++) {
41408                 plugin_config *s;
41409  #if defined(HAVE_PCRE_H)
41410                 const char *errptr;
41411                 int erroff;
41412  #endif
41413 -               
41414 +
41415                 s = calloc(1, sizeof(plugin_config));
41416                 s->db_filename    = buffer_init();
41417                 s->download_url   = buffer_init();
41418 @@ -158,7 +158,7 @@
41419                 s->deny_url       = buffer_init();
41420                 s->mc_hosts       = array_init();
41421                 s->mc_namespace   = buffer_init();
41422 -               
41423 +
41424                 cv[0].destination = s->db_filename;
41425                 cv[1].destination = s->trigger_url;
41426                 cv[2].destination = s->download_url;
41427 @@ -167,41 +167,41 @@
41428                 cv[5].destination = s->mc_hosts;
41429                 cv[6].destination = s->mc_namespace;
41430                 cv[7].destination = &(s->debug);
41431 -               
41432 +
41433                 p->config_storage[i] = s;
41434 -       
41435 +
41436                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
41437                         return HANDLER_ERROR;
41438                 }
41439  #if defined(HAVE_GDBM_H)
41440                 if (!buffer_is_empty(s->db_filename)) {
41441                         if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) {
41442 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
41443 +                               log_error_write(srv, __FILE__, __LINE__, "s",
41444                                                 "gdbm-open failed");
41445                                 return HANDLER_ERROR;
41446                         }
41447                 }
41448  #endif
41449 -#if defined(HAVE_PCRE_H)               
41450 +#if defined(HAVE_PCRE_H)
41451                 if (!buffer_is_empty(s->download_url)) {
41452                         if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr,
41453                                                                       0, &errptr, &erroff, NULL))) {
41454 -                               
41455 -                               log_error_write(srv, __FILE__, __LINE__, "sbss", 
41456 -                                               "compiling regex for download-url failed:", 
41457 +
41458 +                               log_error_write(srv, __FILE__, __LINE__, "sbss",
41459 +                                               "compiling regex for download-url failed:",
41460                                                 s->download_url, "pos:", erroff);
41461                                 return HANDLER_ERROR;
41462                         }
41463                 }
41464 -               
41465 +
41466                 if (!buffer_is_empty(s->trigger_url)) {
41467                         if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr,
41468                                                                      0, &errptr, &erroff, NULL))) {
41469 -                               
41470 -                               log_error_write(srv, __FILE__, __LINE__, "sbss", 
41471 -                                               "compiling regex for trigger-url failed:", 
41472 +
41473 +                               log_error_write(srv, __FILE__, __LINE__, "sbss",
41474 +                                               "compiling regex for trigger-url failed:",
41475                                                 s->trigger_url, "pos:", erroff);
41476 -                               
41477 +
41478                                 return HANDLER_ERROR;
41479                         }
41480                 }
41481 @@ -211,100 +211,97 @@
41482  #if defined(HAVE_MEMCACHE_H)
41483                         size_t k;
41484                         s->mc = mc_new();
41485 -               
41486 +
41487                         for (k = 0; k < s->mc_hosts->used; k++) {
41488                                 data_string *ds = (data_string *)s->mc_hosts->data[k];
41489 -                               
41490 +
41491                                 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
41492 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
41493 -                                                       "connection to host failed:", 
41494 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
41495 +                                                       "connection to host failed:",
41496                                                         ds->value);
41497 -                                       
41498 +
41499                                         return HANDLER_ERROR;
41500                                 }
41501                         }
41502  #else
41503 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
41504 +                       log_error_write(srv, __FILE__, __LINE__, "s",
41505                                         "memcache support is not compiled in but trigger-before-download.memcache-hosts is set, aborting");
41506                         return HANDLER_ERROR;
41507  #endif
41508                 }
41509 -               
41510 +
41511  
41512  #if (!defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)) || !defined(HAVE_PCRE_H)
41513 -               log_error_write(srv, __FILE__, __LINE__, "s", 
41514 +               log_error_write(srv, __FILE__, __LINE__, "s",
41515                                 "(either gdbm or libmemcache) and pcre are require, but were not found, aborting");
41516                 return HANDLER_ERROR;
41517  #endif
41518         }
41519 -       
41520 +
41521         return HANDLER_GO_ON;
41522  }
41523  
41524 -#define PATCH(x) \
41525 -       p->conf.x = s->x;
41526  static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plugin_data *p) {
41527         size_t i, j;
41528         plugin_config *s = p->config_storage[0];
41529 -       
41530 +
41531  #if defined(HAVE_GDBM)
41532 -       PATCH(db);
41533 -#endif 
41534 +       PATCH_OPTION(db);
41535 +#endif
41536  #if defined(HAVE_PCRE_H)
41537 -       PATCH(download_regex);
41538 -       PATCH(trigger_regex);
41539 -#endif 
41540 -       PATCH(trigger_timeout);
41541 -       PATCH(deny_url);
41542 -       PATCH(mc_namespace);
41543 -       PATCH(debug);
41544 +       PATCH_OPTION(download_regex);
41545 +       PATCH_OPTION(trigger_regex);
41546 +#endif
41547 +       PATCH_OPTION(trigger_timeout);
41548 +       PATCH_OPTION(deny_url);
41549 +       PATCH_OPTION(mc_namespace);
41550 +       PATCH_OPTION(debug);
41551  #if defined(HAVE_MEMCACHE_H)
41552 -       PATCH(mc);
41553 +       PATCH_OPTION(mc);
41554  #endif
41555 -       
41556 +
41557         /* skip the first, the global context */
41558         for (i = 1; i < srv->config_context->used; i++) {
41559                 data_config *dc = (data_config *)srv->config_context->data[i];
41560                 s = p->config_storage[i];
41561 -               
41562 +
41563                 /* condition didn't match */
41564                 if (!config_check_cond(srv, con, dc)) continue;
41565 -               
41566 +
41567                 /* merge config */
41568                 for (j = 0; j < dc->value->used; j++) {
41569                         data_unset *du = dc->value->data[j];
41570  
41571                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.download-url"))) {
41572  #if defined(HAVE_PCRE_H)
41573 -                               PATCH(download_regex);
41574 +                               PATCH_OPTION(download_regex);
41575  #endif
41576                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-url"))) {
41577  # if defined(HAVE_PCRE_H)
41578 -                               PATCH(trigger_regex);
41579 +                               PATCH_OPTION(trigger_regex);
41580  # endif
41581                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.gdbm-filename"))) {
41582  #if defined(HAVE_GDBM_H)
41583 -                               PATCH(db);
41584 +                               PATCH_OPTION(db);
41585  #endif
41586                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-timeout"))) {
41587 -                               PATCH(trigger_timeout);
41588 +                               PATCH_OPTION(trigger_timeout);
41589                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.debug"))) {
41590 -                               PATCH(debug);
41591 +                               PATCH_OPTION(debug);
41592                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.deny-url"))) {
41593 -                               PATCH(deny_url);
41594 +                               PATCH_OPTION(deny_url);
41595                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-namespace"))) {
41596 -                               PATCH(mc_namespace);
41597 +                               PATCH_OPTION(mc_namespace);
41598                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-hosts"))) {
41599  #if defined(HAVE_MEMCACHE_H)
41600 -                               PATCH(mc);
41601 +                               PATCH_OPTION(mc);
41602  #endif
41603                         }
41604                 }
41605         }
41606 -       
41607 +
41608         return 0;
41609  }
41610 -#undef PATCH
41611  
41612  URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
41613         plugin_data *p = p_d;
41614 @@ -315,20 +312,20 @@
41615         int n;
41616  # define N 10
41617         int ovec[N * 3];
41618 -       
41619 +
41620         if (con->uri.path->used == 0) return HANDLER_GO_ON;
41621 -       
41622 +
41623         mod_trigger_b4_dl_patch_connection(srv, con, p);
41624 -       
41625 +
41626         if (!p->conf.trigger_regex || !p->conf.download_regex) return HANDLER_GO_ON;
41627 -       
41628 +
41629  # if !defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)
41630         return HANDLER_GO_ON;
41631  # elif defined(HAVE_GDBM_H) && defined(HAVE_MEMCACHE_H)
41632         if (!p->conf.db && !p->conf.mc) return HANDLER_GO_ON;
41633         if (p->conf.db && p->conf.mc) {
41634                 /* can't decide which one */
41635 -               
41636 +
41637                 return HANDLER_GO_ON;
41638         }
41639  # elif defined(HAVE_GDBM_H)
41640 @@ -336,12 +333,12 @@
41641  # else
41642         if (!p->conf.mc) return HANDLER_GO_ON;
41643  # endif
41644 -       
41645 +
41646         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "X-Forwarded-For"))) {
41647                 /* X-Forwarded-For contains the ip behind the proxy */
41648 -               
41649 +
41650                 remote_ip = ds->value->ptr;
41651 -               
41652 +
41653                 /* memcache can't handle spaces */
41654         } else {
41655                 remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
41656 @@ -350,13 +347,13 @@
41657         if (p->conf.debug) {
41658                 log_error_write(srv, __FILE__, __LINE__, "ss", "(debug) remote-ip:", remote_ip);
41659         }
41660 -               
41661 +
41662         /* check if URL is a trigger -> insert IP into DB */
41663         if ((n = pcre_exec(p->conf.trigger_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
41664                 if (n != PCRE_ERROR_NOMATCH) {
41665                         log_error_write(srv, __FILE__, __LINE__, "sd",
41666                                         "execution error while matching:", n);
41667 -                       
41668 +
41669                         return HANDLER_ERROR;
41670                 }
41671         } else {
41672 @@ -364,34 +361,34 @@
41673                 if (p->conf.db) {
41674                         /* the trigger matched */
41675                         datum key, val;
41676 -                       
41677 +
41678                         key.dptr = (char *)remote_ip;
41679                         key.dsize = strlen(remote_ip);
41680 -                       
41681 +
41682                         val.dptr = (char *)&(srv->cur_ts);
41683                         val.dsize = sizeof(srv->cur_ts);
41684 -                       
41685 +
41686                         if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
41687                                 log_error_write(srv, __FILE__, __LINE__, "s",
41688                                                 "insert failed");
41689                         }
41690                 }
41691  # endif
41692 -# if defined(HAVE_MEMCACHE_H)          
41693 +# if defined(HAVE_MEMCACHE_H)
41694                 if (p->conf.mc) {
41695                         size_t i;
41696                         buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
41697                         buffer_append_string(p->tmp_buf, remote_ip);
41698 -                       
41699 +
41700                         for (i = 0; i < p->tmp_buf->used - 1; i++) {
41701                                 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
41702                         }
41703 -                       
41704 +
41705                         if (p->conf.debug) {
41706                                 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) triggered IP:", p->tmp_buf);
41707                         }
41708  
41709 -                       if (0 != mc_set(p->conf.mc, 
41710 +                       if (0 != mc_set(p->conf.mc,
41711                                         CONST_BUF_LEN(p->tmp_buf),
41712                                         (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
41713                                         p->conf.trigger_timeout, 0)) {
41714 @@ -401,7 +398,7 @@
41715                 }
41716  # endif
41717         }
41718 -               
41719 +
41720         /* check if URL is a download -> check IP in DB, update timestamp */
41721         if ((n = pcre_exec(p->conf.download_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
41722                 if (n != PCRE_ERROR_NOMATCH) {
41723 @@ -411,93 +408,93 @@
41724                 }
41725         } else {
41726                 /* the download uri matched */
41727 -# if defined(HAVE_GDBM_H)              
41728 +# if defined(HAVE_GDBM_H)
41729                 if (p->conf.db) {
41730                         datum key, val;
41731                         time_t last_hit;
41732 -               
41733 +
41734                         key.dptr = (char *)remote_ip;
41735                         key.dsize = strlen(remote_ip);
41736 -                       
41737 +
41738                         val = gdbm_fetch(p->conf.db, key);
41739 -               
41740 +
41741                         if (val.dptr == NULL) {
41742                                 /* not found, redirect */
41743 -                               
41744 +
41745                                 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41746 -                               
41747 +
41748                                 con->http_status = 307;
41749 -                               
41750 +
41751                                 return HANDLER_FINISHED;
41752                         }
41753 -                       
41754 +
41755                         last_hit = *(time_t *)(val.dptr);
41756 -                       
41757 +
41758                         free(val.dptr);
41759 -                       
41760 +
41761                         if (srv->cur_ts - last_hit > p->conf.trigger_timeout) {
41762                                 /* found, but timeout, redirect */
41763 -                               
41764 +
41765                                 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41766                                 con->http_status = 307;
41767 -                               
41768 +
41769                                 if (p->conf.db) {
41770                                         if (0 != gdbm_delete(p->conf.db, key)) {
41771                                                 log_error_write(srv, __FILE__, __LINE__, "s",
41772                                                                 "delete failed");
41773                                         }
41774                                 }
41775 -                               
41776 +
41777                                 return HANDLER_FINISHED;
41778                         }
41779 -                       
41780 +
41781                         val.dptr = (char *)&(srv->cur_ts);
41782                         val.dsize = sizeof(srv->cur_ts);
41783 -                       
41784 +
41785                         if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
41786                                 log_error_write(srv, __FILE__, __LINE__, "s",
41787                                                 "insert failed");
41788                         }
41789                 }
41790  # endif
41791 -               
41792 -# if defined(HAVE_MEMCACHE_H)          
41793 +
41794 +# if defined(HAVE_MEMCACHE_H)
41795                 if (p->conf.mc) {
41796                         void *r;
41797                         size_t i;
41798 -                       
41799 +
41800                         buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
41801                         buffer_append_string(p->tmp_buf, remote_ip);
41802 -                       
41803 +
41804                         for (i = 0; i < p->tmp_buf->used - 1; i++) {
41805                                 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
41806                         }
41807 -                       
41808 +
41809                         if (p->conf.debug) {
41810                                 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) checking IP:", p->tmp_buf);
41811                         }
41812  
41813                         /**
41814 -                        * 
41815 +                        *
41816                          * memcached is do expiration for us, as long as we can fetch it every thing is ok
41817 -                        * and the timestamp is updated 
41818 -                        * 
41819 +                        * and the timestamp is updated
41820 +                        *
41821                          */
41822 -                       if (NULL == (r = mc_aget(p->conf.mc, 
41823 +                       if (NULL == (r = mc_aget(p->conf.mc,
41824                                                  CONST_BUF_LEN(p->tmp_buf)
41825                                                  ))) {
41826 -                               
41827 +
41828                                 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41829 -                               
41830 +
41831                                 con->http_status = 307;
41832 -                               
41833 +
41834                                 return HANDLER_FINISHED;
41835                         }
41836 -                       
41837 +
41838                         free(r);
41839 -                       
41840 +
41841                         /* set a new timeout */
41842 -                       if (0 != mc_set(p->conf.mc, 
41843 +                       if (0 != mc_set(p->conf.mc,
41844                                         CONST_BUF_LEN(p->tmp_buf),
41845                                         (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
41846                                         p->conf.trigger_timeout, 0)) {
41847 @@ -507,13 +504,13 @@
41848                 }
41849  # endif
41850         }
41851 -       
41852 +
41853  #else
41854         UNUSED(srv);
41855         UNUSED(con);
41856         UNUSED(p_d);
41857  #endif
41858 -       
41859 +
41860         return HANDLER_GO_ON;
41861  }
41862  
41863 @@ -521,21 +518,21 @@
41864  TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
41865         plugin_data *p = p_d;
41866         size_t i;
41867 -       
41868 +
41869         /* check DB each minute */
41870         if (srv->cur_ts % 60 != 0) return HANDLER_GO_ON;
41871 -       
41872 +
41873         /* cleanup */
41874         for (i = 0; i < srv->config_context->used; i++) {
41875                 plugin_config *s = p->config_storage[i];
41876                 datum key, val, okey;
41877 -               
41878 +
41879                 if (!s->db) continue;
41880 -               
41881 +
41882                 okey.dptr = NULL;
41883 -               
41884 -               /* according to the manual this loop + delete does delete all entries on its way 
41885 -                * 
41886 +
41887 +               /* according to the manual this loop + delete does delete all entries on its way
41888 +                *
41889                  * we don't care as the next round will remove them. We don't have to perfect here.
41890                  */
41891                 for (key = gdbm_firstkey(s->db); key.dptr; key = gdbm_nextkey(s->db, okey)) {
41892 @@ -544,21 +541,21 @@
41893                                 free(okey.dptr);
41894                                 okey.dptr = NULL;
41895                         }
41896 -                       
41897 +
41898                         val = gdbm_fetch(s->db, key);
41899 -                       
41900 +
41901                         last_hit = *(time_t *)(val.dptr);
41902 -                       
41903 +
41904                         free(val.dptr);
41905 -                       
41906 +
41907                         if (srv->cur_ts - last_hit > s->trigger_timeout) {
41908                                 gdbm_delete(s->db, key);
41909                         }
41910 -                       
41911 +
41912                         okey = key;
41913                 }
41914                 if (okey.dptr) free(okey.dptr);
41915 -               
41916 +
41917                 /* reorg once a day */
41918                 if ((srv->cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(s->db);
41919         }
41920 @@ -571,7 +568,7 @@
41921  int mod_trigger_b4_dl_plugin_init(plugin *p) {
41922         p->version     = LIGHTTPD_VERSION_ID;
41923         p->name        = buffer_init_string("trigger_b4_dl");
41924 -       
41925 +
41926         p->init        = mod_trigger_b4_dl_init;
41927         p->handle_uri_clean  = mod_trigger_b4_dl_uri_handler;
41928         p->set_defaults  = mod_trigger_b4_dl_set_defaults;
41929 @@ -579,8 +576,8 @@
41930         p->handle_trigger  = mod_trigger_b4_dl_handle_trigger;
41931  #endif
41932         p->cleanup     = mod_trigger_b4_dl_free;
41933 -       
41934 +
41935         p->data        = NULL;
41936 -       
41937 +
41938         return 0;
41939  }
41940 --- ../lighttpd-1.4.11/src/mod_userdir.c        2005-10-28 16:48:28.000000000 +0300
41941 +++ lighttpd-1.4.12/src/mod_userdir.c   2006-07-16 00:26:04.000000000 +0300
41942 @@ -10,6 +10,7 @@
41943  #include "response.h"
41944  
41945  #include "plugin.h"
41946 +#include "sys-files.h"
41947  
41948  #ifdef HAVE_PWD_H
41949  #include <pwd.h>
41950 @@ -25,54 +26,54 @@
41951  
41952  typedef struct {
41953         PLUGIN_DATA;
41954 -       
41955 +
41956         buffer *username;
41957         buffer *temp_path;
41958 -       
41959 +
41960         plugin_config **config_storage;
41961 -       
41962 -       plugin_config conf; 
41963 +
41964 +       plugin_config conf;
41965  } plugin_data;
41966  
41967  /* init the plugin data */
41968  INIT_FUNC(mod_userdir_init) {
41969         plugin_data *p;
41970 -       
41971 +
41972         p = calloc(1, sizeof(*p));
41973 -       
41974 +
41975         p->username = buffer_init();
41976         p->temp_path = buffer_init();
41977 -       
41978 +
41979         return p;
41980  }
41981  
41982  /* detroy the plugin data */
41983  FREE_FUNC(mod_userdir_free) {
41984         plugin_data *p = p_d;
41985 -       
41986 +
41987         if (!p) return HANDLER_GO_ON;
41988 -       
41989 +
41990         if (p->config_storage) {
41991                 size_t i;
41992 -               
41993 +
41994                 for (i = 0; i < srv->config_context->used; i++) {
41995                         plugin_config *s = p->config_storage[i];
41996 -                       
41997 +
41998                         array_free(s->include_user);
41999                         array_free(s->exclude_user);
42000                         buffer_free(s->path);
42001                         buffer_free(s->basepath);
42002 -                       
42003 +
42004                         free(s);
42005                 }
42006                 free(p->config_storage);
42007         }
42008 -       
42009 +
42010         buffer_free(p->username);
42011         buffer_free(p->temp_path);
42012 -       
42013 +
42014         free(p);
42015 -       
42016 +
42017         return HANDLER_GO_ON;
42018  }
42019  
42020 @@ -81,81 +82,78 @@
42021  SETDEFAULTS_FUNC(mod_userdir_set_defaults) {
42022         plugin_data *p = p_d;
42023         size_t i;
42024 -       
42025 -       config_values_t cv[] = { 
42026 +
42027 +       config_values_t cv[] = {
42028                 { "userdir.path",               NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
42029                 { "userdir.exclude-user",       NULL, T_CONFIG_ARRAY,  T_CONFIG_SCOPE_CONNECTION },       /* 1 */
42030                 { "userdir.include-user",       NULL, T_CONFIG_ARRAY,  T_CONFIG_SCOPE_CONNECTION },       /* 2 */
42031                 { "userdir.basepath",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
42032                 { NULL,                         NULL, T_CONFIG_UNSET,  T_CONFIG_SCOPE_UNSET }
42033         };
42034 -       
42035 +
42036         if (!p) return HANDLER_ERROR;
42037 -       
42038 +
42039         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42040 -       
42041 +
42042         for (i = 0; i < srv->config_context->used; i++) {
42043                 plugin_config *s;
42044 -               
42045 +
42046                 s = calloc(1, sizeof(plugin_config));
42047                 s->exclude_user = array_init();
42048                 s->include_user = array_init();
42049                 s->path = buffer_init();
42050                 s->basepath = buffer_init();
42051 -       
42052 +
42053                 cv[0].destination = s->path;
42054                 cv[1].destination = s->exclude_user;
42055                 cv[2].destination = s->include_user;
42056                 cv[3].destination = s->basepath;
42057 -               
42058 +
42059                 p->config_storage[i] = s;
42060 -       
42061 +
42062                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42063                         return HANDLER_ERROR;
42064                 }
42065         }
42066 -       
42067 +
42068         return HANDLER_GO_ON;
42069  }
42070  
42071 -#define PATCH(x) \
42072 -       p->conf.x = s->x;
42073  static int mod_userdir_patch_connection(server *srv, connection *con, plugin_data *p) {
42074         size_t i, j;
42075         plugin_config *s = p->config_storage[0];
42076 -       
42077 -       PATCH(path);
42078 -       PATCH(exclude_user);
42079 -       PATCH(include_user);
42080 -       PATCH(basepath);
42081 -       
42082 +
42083 +       PATCH_OPTION(path);
42084 +       PATCH_OPTION(exclude_user);
42085 +       PATCH_OPTION(include_user);
42086 +       PATCH_OPTION(basepath);
42087 +
42088         /* skip the first, the global context */
42089         for (i = 1; i < srv->config_context->used; i++) {
42090                 data_config *dc = (data_config *)srv->config_context->data[i];
42091                 s = p->config_storage[i];
42092 -               
42093 +
42094                 /* condition didn't match */
42095                 if (!config_check_cond(srv, con, dc)) continue;
42096 -               
42097 +
42098                 /* merge config */
42099                 for (j = 0; j < dc->value->used; j++) {
42100                         data_unset *du = dc->value->data[j];
42101 -                       
42102 +
42103                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.path"))) {
42104 -                               PATCH(path);
42105 +                               PATCH_OPTION(path);
42106                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.exclude-user"))) {
42107 -                               PATCH(exclude_user);
42108 +                               PATCH_OPTION(exclude_user);
42109                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.include-user"))) {
42110 -                               PATCH(include_user);
42111 +                               PATCH_OPTION(include_user);
42112                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.basepath"))) {
42113 -                               PATCH(basepath);
42114 +                               PATCH_OPTION(basepath);
42115                         }
42116                 }
42117         }
42118 -       
42119 +
42120         return 0;
42121  }
42122 -#undef PATCH
42123  
42124  URIHANDLER_FUNC(mod_userdir_docroot_handler) {
42125         plugin_data *p = p_d;
42126 @@ -169,18 +167,18 @@
42127         if (con->uri.path->used == 0) return HANDLER_GO_ON;
42128  
42129         mod_userdir_patch_connection(srv, con, p);
42130 -       
42131 +
42132         uri_len = con->uri.path->used - 1;
42133 -       
42134 +
42135         /* /~user/foo.html -> /home/user/public_html/foo.html */
42136 -       
42137 +
42138         if (con->uri.path->ptr[0] != '/' ||
42139             con->uri.path->ptr[1] != '~') return HANDLER_GO_ON;
42140 -       
42141 +
42142         if (NULL == (rel_url = strchr(con->uri.path->ptr + 2, '/'))) {
42143                 /* / is missing -> redirect to .../ as we are a user - DIRECTORY ! :) */
42144                 http_response_redirect_to_directory(srv, con);
42145 -               
42146 +
42147                 return HANDLER_FINISHED;
42148         }
42149  
42150 @@ -188,10 +186,10 @@
42151         if (0 == rel_url - (con->uri.path->ptr + 2)) {
42152                 return HANDLER_GO_ON;
42153         }
42154 -       
42155 +
42156         buffer_copy_string_len(p->username, con->uri.path->ptr + 2, rel_url - (con->uri.path->ptr + 2));
42157 -       
42158 -       if (buffer_is_empty(p->conf.basepath) 
42159 +
42160 +       if (buffer_is_empty(p->conf.basepath)
42161  #ifdef HAVE_PWD_H
42162             && NULL == (pwd = getpwnam(p->username->ptr))
42163  #endif
42164 @@ -200,31 +198,31 @@
42165                 return HANDLER_GO_ON;
42166         }
42167  
42168 -       
42169 +
42170         for (k = 0; k < p->conf.exclude_user->used; k++) {
42171                 data_string *ds = (data_string *)p->conf.exclude_user->data[k];
42172 -               
42173 +
42174                 if (buffer_is_equal(ds->value, p->username)) {
42175                         /* user in exclude list */
42176                         return HANDLER_GO_ON;
42177                 }
42178         }
42179 -       
42180 +
42181         if (p->conf.include_user->used) {
42182                 int found_user = 0;
42183                 for (k = 0; k < p->conf.include_user->used; k++) {
42184                         data_string *ds = (data_string *)p->conf.include_user->data[k];
42185 -                       
42186 +
42187                         if (buffer_is_equal(ds->value, p->username)) {
42188                                 /* user in include list */
42189                                 found_user = 1;
42190                                 break;
42191                         }
42192                 }
42193 -               
42194 +
42195                 if (!found_user) return HANDLER_GO_ON;
42196         }
42197 -       
42198 +
42199         /* we build the physical path */
42200  
42201         if (buffer_is_empty(p->conf.basepath)) {
42202 @@ -252,23 +250,23 @@
42203                 }
42204  
42205                 buffer_copy_string_buffer(p->temp_path, p->conf.basepath);
42206 -               BUFFER_APPEND_SLASH(p->temp_path);
42207 +               PATHNAME_APPEND_SLASH(p->temp_path);
42208                 buffer_append_string_buffer(p->temp_path, p->username);
42209         }
42210 -       BUFFER_APPEND_SLASH(p->temp_path);
42211 -       buffer_append_string_buffer(p->temp_path, p->conf.path); 
42212 +       PATHNAME_APPEND_SLASH(p->temp_path);
42213 +       buffer_append_string_buffer(p->temp_path, p->conf.path);
42214  
42215         if (buffer_is_empty(p->conf.basepath)) {
42216                 struct stat st;
42217                 int ret;
42218 -               
42219 +
42220                 ret = stat(p->temp_path->ptr, &st);
42221                 if (ret < 0 || S_ISDIR(st.st_mode) != 1) {
42222                         return HANDLER_GO_ON;
42223 -               } 
42224 +               }
42225         }
42226  
42227 -       BUFFER_APPEND_SLASH(p->temp_path);
42228 +       PATHNAME_APPEND_SLASH(p->temp_path);
42229         buffer_append_string(p->temp_path, rel_url + 1); /* skip the / */
42230         buffer_copy_string_buffer(con->physical.path, p->temp_path);
42231  
42232 @@ -282,13 +280,13 @@
42233  int mod_userdir_plugin_init(plugin *p) {
42234         p->version     = LIGHTTPD_VERSION_ID;
42235         p->name        = buffer_init_string("userdir");
42236 -       
42237 +
42238         p->init           = mod_userdir_init;
42239         p->handle_physical = mod_userdir_docroot_handler;
42240         p->set_defaults   = mod_userdir_set_defaults;
42241         p->cleanup        = mod_userdir_free;
42242 -       
42243 +
42244         p->data        = NULL;
42245 -       
42246 +
42247         return 0;
42248  }
42249 --- ../lighttpd-1.4.11/src/mod_usertrack.c      2006-01-31 15:01:20.000000000 +0200
42250 +++ lighttpd-1.4.12/src/mod_usertrack.c 2006-07-16 00:26:04.000000000 +0300
42251 @@ -24,44 +24,44 @@
42252  
42253  typedef struct {
42254         PLUGIN_DATA;
42255 -       
42256 +
42257         plugin_config **config_storage;
42258 -       
42259 -       plugin_config conf; 
42260 +
42261 +       plugin_config conf;
42262  } plugin_data;
42263  
42264  /* init the plugin data */
42265  INIT_FUNC(mod_usertrack_init) {
42266         plugin_data *p;
42267 -       
42268 +
42269         p = calloc(1, sizeof(*p));
42270 -       
42271 +
42272         return p;
42273  }
42274  
42275  /* detroy the plugin data */
42276  FREE_FUNC(mod_usertrack_free) {
42277         plugin_data *p = p_d;
42278 -       
42279 +
42280         UNUSED(srv);
42281 -       
42282 +
42283         if (!p) return HANDLER_GO_ON;
42284 -       
42285 +
42286         if (p->config_storage) {
42287                 size_t i;
42288                 for (i = 0; i < srv->config_context->used; i++) {
42289                         plugin_config *s = p->config_storage[i];
42290 -                       
42291 +
42292                         buffer_free(s->cookie_name);
42293                         buffer_free(s->cookie_domain);
42294 -                       
42295 +
42296                         free(s);
42297                 }
42298                 free(p->config_storage);
42299         }
42300 -       
42301 +
42302         free(p);
42303 -       
42304 +
42305         return HANDLER_GO_ON;
42306  }
42307  
42308 @@ -70,38 +70,38 @@
42309  SETDEFAULTS_FUNC(mod_usertrack_set_defaults) {
42310         plugin_data *p = p_d;
42311         size_t i = 0;
42312 -       
42313 -       config_values_t cv[] = { 
42314 +
42315 +       config_values_t cv[] = {
42316                 { "usertrack.cookie-name",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
42317                 { "usertrack.cookie-max-age",    NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 1 */
42318                 { "usertrack.cookie-domain",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
42319 -               
42320 -               { "usertrack.cookiename",        NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },   
42321 +
42322 +               { "usertrack.cookiename",        NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },
42323                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42324         };
42325 -       
42326 +
42327         if (!p) return HANDLER_ERROR;
42328 -       
42329 +
42330         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42331 -       
42332 +
42333         for (i = 0; i < srv->config_context->used; i++) {
42334                 plugin_config *s;
42335 -               
42336 +
42337                 s = calloc(1, sizeof(plugin_config));
42338                 s->cookie_name    = buffer_init();
42339                 s->cookie_domain  = buffer_init();
42340                 s->cookie_max_age = 0;
42341 -               
42342 +
42343                 cv[0].destination = s->cookie_name;
42344                 cv[1].destination = &(s->cookie_max_age);
42345                 cv[2].destination = s->cookie_domain;
42346 -               
42347 +
42348                 p->config_storage[i] = s;
42349 -       
42350 +
42351                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42352                         return HANDLER_ERROR;
42353                 }
42354 -       
42355 +
42356                 if (buffer_is_empty(s->cookie_name)) {
42357                         buffer_copy_string(s->cookie_name, "TRACKID");
42358                 } else {
42359 @@ -109,68 +109,65 @@
42360                         for (j = 0; j < s->cookie_name->used - 1; j++) {
42361                                 char c = s->cookie_name->ptr[j] | 32;
42362                                 if (c < 'a' || c > 'z') {
42363 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
42364 -                                                       "invalid character in usertrack.cookie-name:", 
42365 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
42366 +                                                       "invalid character in usertrack.cookie-name:",
42367                                                         s->cookie_name);
42368 -                                       
42369 +
42370                                         return HANDLER_ERROR;
42371                                 }
42372                         }
42373                 }
42374 -               
42375 +
42376                 if (!buffer_is_empty(s->cookie_domain)) {
42377                         size_t j;
42378                         for (j = 0; j < s->cookie_domain->used - 1; j++) {
42379                                 char c = s->cookie_domain->ptr[j];
42380                                 if (c <= 32 || c >= 127 || c == '"' || c == '\\') {
42381 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
42382 -                                                       "invalid character in usertrack.cookie-domain:", 
42383 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
42384 +                                                       "invalid character in usertrack.cookie-domain:",
42385                                                         s->cookie_domain);
42386 -                                       
42387 +
42388                                         return HANDLER_ERROR;
42389                                 }
42390                         }
42391                 }
42392         }
42393 -               
42394 +
42395         return HANDLER_GO_ON;
42396  }
42397  
42398 -#define PATCH(x) \
42399 -       p->conf.x = s->x;
42400  static int mod_usertrack_patch_connection(server *srv, connection *con, plugin_data *p) {
42401         size_t i, j;
42402         plugin_config *s = p->config_storage[0];
42403 -       
42404 -       PATCH(cookie_name);
42405 -       PATCH(cookie_domain);
42406 -       PATCH(cookie_max_age);
42407 -       
42408 +
42409 +       PATCH_OPTION(cookie_name);
42410 +       PATCH_OPTION(cookie_domain);
42411 +       PATCH_OPTION(cookie_max_age);
42412 +
42413         /* skip the first, the global context */
42414         for (i = 1; i < srv->config_context->used; i++) {
42415                 data_config *dc = (data_config *)srv->config_context->data[i];
42416                 s = p->config_storage[i];
42417 -               
42418 +
42419                 /* condition didn't match */
42420                 if (!config_check_cond(srv, con, dc)) continue;
42421 -               
42422 +
42423                 /* merge config */
42424                 for (j = 0; j < dc->value->used; j++) {
42425                         data_unset *du = dc->value->data[j];
42426 -                       
42427 +
42428                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-name"))) {
42429 -                               PATCH(cookie_name);
42430 +                               PATCH_OPTION(cookie_name);
42431                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-max-age"))) {
42432 -                               PATCH(cookie_max_age);
42433 +                               PATCH_OPTION(cookie_max_age);
42434                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-domain"))) {
42435 -                               PATCH(cookie_domain);
42436 +                               PATCH_OPTION(cookie_domain);
42437                         }
42438                 }
42439         }
42440 -       
42441 +
42442         return 0;
42443  }
42444 -#undef PATCH
42445  
42446  URIHANDLER_FUNC(mod_usertrack_uri_handler) {
42447         plugin_data *p = p_d;
42448 @@ -178,38 +175,38 @@
42449         unsigned char h[16];
42450         MD5_CTX Md5Ctx;
42451         char hh[32];
42452 -       
42453 +
42454         if (con->uri.path->used == 0) return HANDLER_GO_ON;
42455 -       
42456 +
42457         mod_usertrack_patch_connection(srv, con, p);
42458 -       
42459 +
42460         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
42461                 char *g;
42462                 /* we have a cookie, does it contain a valid name ? */
42463 -               
42464 -               /* parse the cookie 
42465 -                * 
42466 +
42467 +               /* parse the cookie
42468 +                *
42469                  * check for cookiename + (WS | '=')
42470 -                * 
42471 +                *
42472                  */
42473 -               
42474 +
42475                 if (NULL != (g = strstr(ds->value->ptr, p->conf.cookie_name->ptr))) {
42476                         char *nc;
42477 -                       
42478 +
42479                         /* skip WS */
42480                         for (nc = g + p->conf.cookie_name->used-1; *nc == ' ' || *nc == '\t'; nc++);
42481 -                       
42482 +
42483                         if (*nc == '=') {
42484                                 /* ok, found the key of our own cookie */
42485 -                               
42486 +
42487                                 if (strlen(nc) > 32) {
42488                                         /* i'm lazy */
42489                                         return HANDLER_GO_ON;
42490                                 }
42491                         }
42492                 }
42493 -       } 
42494 -       
42495 +       }
42496 +
42497         /* set a cookie */
42498         if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
42499                 ds = data_response_init();
42500 @@ -217,39 +214,39 @@
42501         buffer_copy_string(ds->key, "Set-Cookie");
42502         buffer_copy_string_buffer(ds->value, p->conf.cookie_name);
42503         buffer_append_string(ds->value, "=");
42504 -       
42505 +
42506  
42507         /* taken from mod_auth.c */
42508 -       
42509 +
42510         /* generate shared-secret */
42511         MD5_Init(&Md5Ctx);
42512         MD5_Update(&Md5Ctx, (unsigned char *)con->uri.path->ptr, con->uri.path->used - 1);
42513         MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
42514 -       
42515 +
42516         /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
42517         ltostr(hh, srv->cur_ts);
42518         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
42519         ltostr(hh, rand());
42520         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
42521 -       
42522 +
42523         MD5_Final(h, &Md5Ctx);
42524 -       
42525 +
42526         buffer_append_string_encoded(ds->value, (char *)h, 16, ENCODING_HEX);
42527         buffer_append_string(ds->value, "; Path=/");
42528         buffer_append_string(ds->value, "; Version=1");
42529 -       
42530 +
42531         if (!buffer_is_empty(p->conf.cookie_domain)) {
42532                 buffer_append_string(ds->value, "; Domain=");
42533                 buffer_append_string_encoded(ds->value, CONST_BUF_LEN(p->conf.cookie_domain), ENCODING_REL_URI);
42534         }
42535 -       
42536 +
42537         if (p->conf.cookie_max_age) {
42538                 buffer_append_string(ds->value, "; max-age=");
42539                 buffer_append_long(ds->value, p->conf.cookie_max_age);
42540         }
42541 -       
42542 +
42543         array_insert_unique(con->response.headers, (data_unset *)ds);
42544 -       
42545 +
42546         return HANDLER_GO_ON;
42547  }
42548  
42549 @@ -258,13 +255,13 @@
42550  int mod_usertrack_plugin_init(plugin *p) {
42551         p->version     = LIGHTTPD_VERSION_ID;
42552         p->name        = buffer_init_string("usertrack");
42553 -       
42554 +
42555         p->init        = mod_usertrack_init;
42556         p->handle_uri_clean  = mod_usertrack_uri_handler;
42557         p->set_defaults  = mod_usertrack_set_defaults;
42558         p->cleanup     = mod_usertrack_free;
42559 -       
42560 +
42561         p->data        = NULL;
42562 -       
42563 +
42564         return 0;
42565  }
42566 --- ../lighttpd-1.4.11/src/mod_webdav.c 2006-03-03 01:28:58.000000000 +0200
42567 +++ lighttpd-1.4.12/src/mod_webdav.c    2006-07-18 13:03:40.000000000 +0300
42568 @@ -3,13 +3,10 @@
42569  #include <ctype.h>
42570  #include <stdlib.h>
42571  #include <string.h>
42572 -#include <dirent.h>
42573  #include <errno.h>
42574 -#include <unistd.h>
42575  #include <fcntl.h>
42576  #include <stdio.h>
42577  #include <assert.h>
42578 -#include <sys/mman.h>
42579  
42580  #ifdef HAVE_CONFIG_H
42581  #include "config.h"
42582 @@ -23,6 +20,11 @@
42583  #include <sqlite3.h>
42584  #endif
42585  
42586 +#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H) && defined(HAVE_UUID_H)
42587 +#define USE_LOCKS
42588 +#include <uuid/uuid.h>
42589 +#endif
42590 +
42591  #include "base.h"
42592  #include "log.h"
42593  #include "buffer.h"
42594 @@ -33,13 +35,16 @@
42595  #include "stream.h"
42596  #include "stat_cache.h"
42597  
42598 +#include "sys-files.h"
42599 +#include "sys-mmap.h"
42600 +#include "sys-strings.h"
42601  
42602  /**
42603   * this is a webdav for a lighttpd plugin
42604   *
42605 - * at least a very basic one. 
42606 + * at least a very basic one.
42607   * - for now it is read-only and we only support PROPFIND
42608 - * 
42609 + *
42610   */
42611  
42612  
42613 @@ -58,64 +63,70 @@
42614         sqlite3_stmt *stmt_delete_prop;
42615         sqlite3_stmt *stmt_select_prop;
42616         sqlite3_stmt *stmt_select_propnames;
42617 -       
42618 +
42619         sqlite3_stmt *stmt_delete_uri;
42620         sqlite3_stmt *stmt_move_uri;
42621         sqlite3_stmt *stmt_copy_uri;
42622 +
42623 +       sqlite3_stmt *stmt_remove_lock;
42624 +       sqlite3_stmt *stmt_create_lock;
42625 +       sqlite3_stmt *stmt_read_lock;
42626 +       sqlite3_stmt *stmt_read_lock_by_uri;
42627 +       sqlite3_stmt *stmt_refresh_lock;
42628  #endif
42629  } plugin_config;
42630  
42631  typedef struct {
42632         PLUGIN_DATA;
42633 -       
42634 +
42635         buffer *tmp_buf;
42636         request_uri uri;
42637         physical physical;
42638  
42639         plugin_config **config_storage;
42640 -       
42641 -       plugin_config conf; 
42642 +
42643 +       plugin_config conf;
42644  } plugin_data;
42645  
42646  /* init the plugin data */
42647  INIT_FUNC(mod_webdav_init) {
42648         plugin_data *p;
42649 -       
42650 +
42651         p = calloc(1, sizeof(*p));
42652 -       
42653 +
42654         p->tmp_buf = buffer_init();
42655  
42656         p->uri.scheme = buffer_init();
42657         p->uri.path_raw = buffer_init();
42658         p->uri.path = buffer_init();
42659         p->uri.authority = buffer_init();
42660 -       
42661 +
42662         p->physical.path = buffer_init();
42663         p->physical.rel_path = buffer_init();
42664         p->physical.doc_root = buffer_init();
42665         p->physical.basedir = buffer_init();
42666 -       
42667 +
42668         return p;
42669  }
42670  
42671  /* detroy the plugin data */
42672  FREE_FUNC(mod_webdav_free) {
42673         plugin_data *p = p_d;
42674 -       
42675 +
42676         UNUSED(srv);
42677  
42678         if (!p) return HANDLER_GO_ON;
42679 -       
42680 +
42681         if (p->config_storage) {
42682                 size_t i;
42683                 for (i = 0; i < srv->config_context->used; i++) {
42684                         plugin_config *s = p->config_storage[i];
42685  
42686                         if (!s) continue;
42687 -       
42688 +
42689                         buffer_free(s->sqlite_db_name);
42690  #ifdef USE_PROPPATCH
42691 -                       if (s->sql) {   
42692 +                       if (s->sql) {
42693                                 sqlite3_finalize(s->stmt_delete_prop);
42694                                 sqlite3_finalize(s->stmt_delete_uri);
42695                                 sqlite3_finalize(s->stmt_copy_uri);
42696 @@ -123,9 +134,15 @@
42697                                 sqlite3_finalize(s->stmt_update_prop);
42698                                 sqlite3_finalize(s->stmt_select_prop);
42699                                 sqlite3_finalize(s->stmt_select_propnames);
42700 +
42701 +                               sqlite3_finalize(s->stmt_read_lock);
42702 +                               sqlite3_finalize(s->stmt_read_lock_by_uri);
42703 +                               sqlite3_finalize(s->stmt_create_lock);
42704 +                               sqlite3_finalize(s->stmt_remove_lock);
42705 +                               sqlite3_finalize(s->stmt_refresh_lock);
42706                                 sqlite3_close(s->sql);
42707                         }
42708 -#endif 
42709 +#endif
42710                         free(s);
42711                 }
42712                 free(p->config_storage);
42713 @@ -135,16 +152,16 @@
42714         buffer_free(p->uri.path_raw);
42715         buffer_free(p->uri.path);
42716         buffer_free(p->uri.authority);
42717 -       
42718 +
42719         buffer_free(p->physical.path);
42720         buffer_free(p->physical.rel_path);
42721         buffer_free(p->physical.doc_root);
42722         buffer_free(p->physical.basedir);
42723 -       
42724 +
42725         buffer_free(p->tmp_buf);
42726 -       
42727 +
42728         free(p);
42729 -       
42730 +
42731         return HANDLER_GO_ON;
42732  }
42733  
42734 @@ -153,32 +170,32 @@
42735  SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
42736         plugin_data *p = p_d;
42737         size_t i = 0;
42738 -       
42739 -       config_values_t cv[] = { 
42740 +
42741 +       config_values_t cv[] = {
42742                 { "webdav.activate",            NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
42743                 { "webdav.is-readonly",         NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
42744                 { "webdav.sqlite-db-name",      NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION },       /* 2 */
42745                 { "webdav.log-xml",             NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
42746                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42747         };
42748 -       
42749 +
42750         if (!p) return HANDLER_ERROR;
42751 -       
42752 +
42753         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42754 -       
42755 +
42756         for (i = 0; i < srv->config_context->used; i++) {
42757                 plugin_config *s;
42758 -               
42759 +
42760                 s = calloc(1, sizeof(plugin_config));
42761                 s->sqlite_db_name = buffer_init();
42762 -               
42763 +
42764                 cv[0].destination = &(s->enabled);
42765                 cv[1].destination = &(s->is_readonly);
42766                 cv[2].destination = s->sqlite_db_name;
42767                 cv[3].destination = &(s->log_xml);
42768 -               
42769 +
42770                 p->config_storage[i] = s;
42771 -       
42772 +
42773                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42774                         return HANDLER_ERROR;
42775                 }
42776 @@ -193,8 +210,26 @@
42777                                 return HANDLER_ERROR;
42778                         }
42779  
42780 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42781 -                               CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"), 
42782 +                       if (SQLITE_OK != sqlite3_exec(s->sql,
42783 +                                       "CREATE TABLE properties ("
42784 +                                       "  resource TEXT NOT NULL,"
42785 +                                       "  prop TEXT NOT NULL,"
42786 +                                       "  ns TEXT NOT NULL,"
42787 +                                       "  value TEXT NOT NULL,"
42788 +                                       "  PRIMARY KEY(resource, prop, ns))",
42789 +                                       NULL, NULL, &err)) {
42790 +
42791 +                               if (0 != strcmp(err, "table properties already exists")) {
42792 +                                       log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
42793 +                                       sqlite3_free(err);
42794 +
42795 +                                       return HANDLER_ERROR;
42796 +                               }
42797 +                               sqlite3_free(err);
42798 +                       }
42799 +
42800 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42801 +                               CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42802                                 &(s->stmt_select_prop), &next_stmt)) {
42803                                 /* prepare failed */
42804  
42805 @@ -202,8 +237,8 @@
42806                                 return HANDLER_ERROR;
42807                         }
42808  
42809 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42810 -                               CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"), 
42811 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42812 +                               CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"),
42813                                 &(s->stmt_select_propnames), &next_stmt)) {
42814                                 /* prepare failed */
42815  
42816 @@ -211,16 +246,67 @@
42817                                 return HANDLER_ERROR;
42818                         }
42819  
42820 -                       if (SQLITE_OK != sqlite3_exec(s->sql, 
42821 -                                       "CREATE TABLE properties ("
42822 +
42823 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42824 +                               CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"),
42825 +                               &(s->stmt_update_prop), &next_stmt)) {
42826 +                               /* prepare failed */
42827 +
42828 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
42829 +                               return HANDLER_ERROR;
42830 +                       }
42831 +
42832 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42833 +                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42834 +                               &(s->stmt_delete_prop), &next_stmt)) {
42835 +                               /* prepare failed */
42836 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42837 +
42838 +                               return HANDLER_ERROR;
42839 +                       }
42840 +
42841 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42842 +                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"),
42843 +                               &(s->stmt_delete_uri), &next_stmt)) {
42844 +                               /* prepare failed */
42845 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42846 +
42847 +                               return HANDLER_ERROR;
42848 +                       }
42849 +
42850 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42851 +                               CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"),
42852 +                               &(s->stmt_copy_uri), &next_stmt)) {
42853 +                               /* prepare failed */
42854 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42855 +
42856 +                               return HANDLER_ERROR;
42857 +                       }
42858 +
42859 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42860 +                               CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"),
42861 +                               &(s->stmt_move_uri), &next_stmt)) {
42862 +                               /* prepare failed */
42863 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42864 +
42865 +                               return HANDLER_ERROR;
42866 +                       }
42867 +
42868 +                       /* LOCKS */
42869 +
42870 +                       if (SQLITE_OK != sqlite3_exec(s->sql,
42871 +                                       "CREATE TABLE locks ("
42872 +                                       "  locktoken TEXT NOT NULL,"
42873                                         "  resource TEXT NOT NULL,"
42874 -                                       "  prop TEXT NOT NULL,"
42875 -                                       "  ns TEXT NOT NULL,"
42876 -                                       "  value TEXT NOT NULL,"
42877 -                                       "  PRIMARY KEY(resource, prop, ns))",
42878 +                                       "  lockscope TEXT NOT NULL,"
42879 +                                       "  locktype TEXT NOT NULL,"
42880 +                                       "  owner TEXT NOT NULL,"
42881 +                                       "  depth INT NOT NULL,"
42882 +                                       "  timeout TIMESTAMP NOT NULL,"
42883 +                                       "  PRIMARY KEY(locktoken))",
42884                                         NULL, NULL, &err)) {
42885  
42886 -                               if (0 != strcmp(err, "table properties already exists")) {
42887 +                               if (0 != strcmp(err, "table locks already exists")) {
42888                                         log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
42889                                         sqlite3_free(err);
42890  
42891 @@ -228,127 +314,138 @@
42892                                 }
42893                                 sqlite3_free(err);
42894                         }
42895 -       
42896 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42897 -                               CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"), 
42898 -                               &(s->stmt_update_prop), &next_stmt)) {
42899 +
42900 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42901 +                               CONST_STR_LEN("INSERT INTO locks (locktoken, resource, lockscope, locktype, owner, depth, timeout) VALUES (?,?,?,?,?,?, CURRENT_TIME + 600)"),
42902 +                               &(s->stmt_create_lock), &next_stmt)) {
42903                                 /* prepare failed */
42904 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42905  
42906 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
42907                                 return HANDLER_ERROR;
42908                         }
42909  
42910 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42911 -                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"), 
42912 -                               &(s->stmt_delete_prop), &next_stmt)) {
42913 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42914 +                               CONST_STR_LEN("DELETE FROM locks WHERE locktoken = ?"),
42915 +                               &(s->stmt_remove_lock), &next_stmt)) {
42916                                 /* prepare failed */
42917                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42918  
42919                                 return HANDLER_ERROR;
42920                         }
42921  
42922 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42923 -                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"), 
42924 -                               &(s->stmt_delete_uri), &next_stmt)) {
42925 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42926 +                               CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE locktoken = ?"),
42927 +                               &(s->stmt_read_lock), &next_stmt)) {
42928                                 /* prepare failed */
42929                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42930  
42931                                 return HANDLER_ERROR;
42932                         }
42933  
42934 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42935 -                               CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"), 
42936 -                               &(s->stmt_copy_uri), &next_stmt)) {
42937 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42938 +                               CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE resource = ?"),
42939 +                               &(s->stmt_read_lock_by_uri), &next_stmt)) {
42940                                 /* prepare failed */
42941                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42942  
42943                                 return HANDLER_ERROR;
42944                         }
42945  
42946 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42947 -                               CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"), 
42948 -                               &(s->stmt_move_uri), &next_stmt)) {
42949 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42950 +                               CONST_STR_LEN("UPDATE locks SET timeout = CURRENT_TIME + 600 WHERE locktoken = ?"),
42951 +                               &(s->stmt_refresh_lock), &next_stmt)) {
42952                                 /* prepare failed */
42953                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42954  
42955                                 return HANDLER_ERROR;
42956                         }
42957 +
42958 +
42959  #else
42960                         log_error_write(srv, __FILE__, __LINE__, "s", "Sorry, no sqlite3 and libxml2 support include, compile with --with-webdav-props");
42961                         return HANDLER_ERROR;
42962  #endif
42963                 }
42964         }
42965 -       
42966 +
42967         return HANDLER_GO_ON;
42968  }
42969  
42970 -#define PATCH(x) \
42971 -       p->conf.x = s->x;
42972  static int mod_webdav_patch_connection(server *srv, connection *con, plugin_data *p) {
42973         size_t i, j;
42974         plugin_config *s = p->config_storage[0];
42975 -       
42976 -       PATCH(enabled);
42977 -       PATCH(is_readonly);
42978 -       PATCH(log_xml);
42979 -       
42980 +
42981 +       PATCH_OPTION(enabled);
42982 +       PATCH_OPTION(is_readonly);
42983 +       PATCH_OPTION(log_xml);
42984 +
42985  #ifdef USE_PROPPATCH
42986 -       PATCH(sql);
42987 -       PATCH(stmt_update_prop);
42988 -       PATCH(stmt_delete_prop);
42989 -       PATCH(stmt_select_prop);
42990 -       PATCH(stmt_select_propnames);
42991 -
42992 -       PATCH(stmt_delete_uri);
42993 -       PATCH(stmt_move_uri);
42994 -       PATCH(stmt_copy_uri);
42995 +       PATCH_OPTION(sql);
42996 +       PATCH_OPTION(stmt_update_prop);
42997 +       PATCH_OPTION(stmt_delete_prop);
42998 +       PATCH_OPTION(stmt_select_prop);
42999 +       PATCH_OPTION(stmt_select_propnames);
43000 +
43001 +       PATCH_OPTION(stmt_delete_uri);
43002 +       PATCH_OPTION(stmt_move_uri);
43003 +       PATCH_OPTION(stmt_copy_uri);
43004 +
43005 +       PATCH_OPTION(stmt_remove_lock);
43006 +       PATCH_OPTION(stmt_refresh_lock);
43007 +       PATCH_OPTION(stmt_create_lock);
43008 +       PATCH_OPTION(stmt_read_lock);
43009 +       PATCH_OPTION(stmt_read_lock_by_uri);
43010  #endif
43011         /* skip the first, the global context */
43012         for (i = 1; i < srv->config_context->used; i++) {
43013                 data_config *dc = (data_config *)srv->config_context->data[i];
43014                 s = p->config_storage[i];
43015 -               
43016 +
43017                 /* condition didn't match */
43018                 if (!config_check_cond(srv, con, dc)) continue;
43019 -               
43020 +
43021                 /* merge config */
43022                 for (j = 0; j < dc->value->used; j++) {
43023                         data_unset *du = dc->value->data[j];
43024 -                       
43025 +
43026                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.activate"))) {
43027 -                               PATCH(enabled);
43028 +                               PATCH_OPTION(enabled);
43029                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.is-readonly"))) {
43030 -                               PATCH(is_readonly);
43031 +                               PATCH_OPTION(is_readonly);
43032                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.log-xml"))) {
43033 -                               PATCH(log_xml);
43034 +                               PATCH_OPTION(log_xml);
43035                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.sqlite-db-name"))) {
43036  #ifdef USE_PROPPATCH
43037 -                               PATCH(sql);
43038 -                               PATCH(stmt_update_prop);
43039 -                               PATCH(stmt_delete_prop);
43040 -                               PATCH(stmt_select_prop);
43041 -                               PATCH(stmt_select_propnames);
43042 -                               
43043 -                               PATCH(stmt_delete_uri);
43044 -                               PATCH(stmt_move_uri);
43045 -                               PATCH(stmt_copy_uri);
43046 +                               PATCH_OPTION(sql);
43047 +                               PATCH_OPTION(stmt_update_prop);
43048 +                               PATCH_OPTION(stmt_delete_prop);
43049 +                               PATCH_OPTION(stmt_select_prop);
43050 +                               PATCH_OPTION(stmt_select_propnames);
43051 +
43052 +                               PATCH_OPTION(stmt_delete_uri);
43053 +                               PATCH_OPTION(stmt_move_uri);
43054 +                               PATCH_OPTION(stmt_copy_uri);
43055 +
43056 +                               PATCH_OPTION(stmt_remove_lock);
43057 +                               PATCH_OPTION(stmt_refresh_lock);
43058 +                               PATCH_OPTION(stmt_create_lock);
43059 +                               PATCH_OPTION(stmt_read_lock);
43060 +                               PATCH_OPTION(stmt_read_lock_by_uri);
43061  #endif
43062                         }
43063                 }
43064         }
43065 -       
43066 +
43067         return 0;
43068  }
43069 -#undef PATCH
43070  
43071  URIHANDLER_FUNC(mod_webdav_uri_handler) {
43072         plugin_data *p = p_d;
43073 -       
43074 +
43075         UNUSED(srv);
43076  
43077         if (con->uri.path->used == 0) return HANDLER_GO_ON;
43078 -       
43079 +
43080         mod_webdav_patch_connection(srv, con, p);
43081  
43082         if (!p->conf.enabled) return HANDLER_GO_ON;
43083 @@ -362,20 +459,20 @@
43084                 if (p->conf.is_readonly) {
43085                         response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND"));
43086                 } else {
43087 -                       response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH"));
43088 +                       response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH, LOCK, UNLOCK"));
43089                 }
43090                 break;
43091         default:
43092                 break;
43093         }
43094 -       
43095 +
43096         /* not found */
43097         return HANDLER_GO_ON;
43098  }
43099 -static int webdav_gen_prop_tag(server *srv, connection *con, 
43100 -               char *prop_name, 
43101 -               char *prop_ns, 
43102 -               char *value, 
43103 +static int webdav_gen_prop_tag(server *srv, connection *con,
43104 +               char *prop_name,
43105 +               char *prop_ns,
43106 +               char *value,
43107                 buffer *b) {
43108  
43109         UNUSED(srv);
43110 @@ -414,7 +511,7 @@
43111         buffer_append_string_buffer(b, dst->rel_path);
43112         buffer_append_string(b,"</D:href>\n");
43113         buffer_append_string(b,"<D:status>\n");
43114 -       
43115 +
43116         if (con->request.http_version == HTTP_VERSION_1_1) {
43117                 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
43118         } else {
43119 @@ -458,14 +555,13 @@
43120  
43121                         /* bind the values to the insert */
43122  
43123 -                       sqlite3_bind_text(stmt, 1, 
43124 -                                         dst->rel_path->ptr, 
43125 +                       sqlite3_bind_text(stmt, 1,
43126 +                                         dst->rel_path->ptr,
43127                                           dst->rel_path->used - 1,
43128                                           SQLITE_TRANSIENT);
43129 -                                                                       
43130 +
43131                         if (SQLITE_DONE != sqlite3_step(stmt)) {
43132                                 /* */
43133 -                               WP();
43134                         }
43135                 }
43136  #endif
43137 @@ -493,14 +589,14 @@
43138                             (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
43139                                 continue;
43140                                 /* ignore the parent dir */
43141 -                       } 
43142 +                       }
43143  
43144                         buffer_copy_string_buffer(d.path, dst->path);
43145 -                       BUFFER_APPEND_SLASH(d.path);
43146 +                       PATHNAME_APPEND_SLASH(d.path);
43147                         buffer_append_string(d.path, de->d_name);
43148 -                       
43149 +
43150                         buffer_copy_string_buffer(d.rel_path, dst->rel_path);
43151 -                       BUFFER_APPEND_SLASH(d.rel_path);
43152 +                       PATHNAME_APPEND_SLASH(d.rel_path);
43153                         buffer_append_string(d.rel_path, de->d_name);
43154  
43155                         /* stat and unlink afterwards */
43156 @@ -508,7 +604,7 @@
43157                                 /* don't about it yet, rmdir will fail too */
43158                         } else if (S_ISDIR(st.st_mode)) {
43159                                 have_multi_status = webdav_delete_dir(srv, con, p, &d, b);
43160 -                                       
43161 +
43162                                 /* try to unlink it */
43163                                 if (-1 == rmdir(d.path->ptr)) {
43164                                         switch(errno) {
43165 @@ -535,14 +631,13 @@
43166  
43167                                                 /* bind the values to the insert */
43168  
43169 -                                               sqlite3_bind_text(stmt, 1, 
43170 -                                                                 d.rel_path->ptr, 
43171 +                                               sqlite3_bind_text(stmt, 1,
43172 +                                                                 d.rel_path->ptr,
43173                                                                   d.rel_path->used - 1,
43174                                                                   SQLITE_TRANSIENT);
43175 -                                                                                                       
43176 +
43177                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
43178                                                         /* */
43179 -                                                       WP();
43180                                                 }
43181                                         }
43182  #endif
43183 @@ -569,7 +664,7 @@
43184         if (stream_open(&s, src->path)) {
43185                 return 403;
43186         }
43187 -                       
43188 +
43189         if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), 0600))) {
43190                 /* opening the destination failed for some reason */
43191                 switch(errno) {
43192 @@ -601,7 +696,7 @@
43193                         break;
43194                 }
43195         }
43196 -       
43197 +
43198         stream_close(&s);
43199         close(ofd);
43200  
43201 @@ -614,19 +709,18 @@
43202                         sqlite3_reset(stmt);
43203  
43204                         /* bind the values to the insert */
43205 -                       sqlite3_bind_text(stmt, 1, 
43206 -                                         dst->rel_path->ptr, 
43207 +                       sqlite3_bind_text(stmt, 1,
43208 +                                         dst->rel_path->ptr,
43209                                           dst->rel_path->used - 1,
43210                                           SQLITE_TRANSIENT);
43211  
43212 -                       sqlite3_bind_text(stmt, 2, 
43213 -                                         src->rel_path->ptr, 
43214 +                       sqlite3_bind_text(stmt, 2,
43215 +                                         src->rel_path->ptr,
43216                                           src->rel_path->used - 1,
43217                                           SQLITE_TRANSIENT);
43218 -                                                                                                       
43219 +
43220                         if (SQLITE_DONE != sqlite3_step(stmt)) {
43221                                 /* */
43222 -                               WP();
43223                         }
43224                 }
43225         }
43226 @@ -655,21 +749,21 @@
43227                             (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
43228                                 continue;
43229                         }
43230 -                       
43231 +
43232                         buffer_copy_string_buffer(s.path, src->path);
43233 -                       BUFFER_APPEND_SLASH(s.path);
43234 +                       PATHNAME_APPEND_SLASH(s.path);
43235                         buffer_append_string(s.path, de->d_name);
43236  
43237                         buffer_copy_string_buffer(d.path, dst->path);
43238 -                       BUFFER_APPEND_SLASH(d.path);
43239 +                       PATHNAME_APPEND_SLASH(d.path);
43240                         buffer_append_string(d.path, de->d_name);
43241  
43242                         buffer_copy_string_buffer(s.rel_path, src->rel_path);
43243 -                       BUFFER_APPEND_SLASH(s.rel_path);
43244 +                       PATHNAME_APPEND_SLASH(s.rel_path);
43245                         buffer_append_string(s.rel_path, de->d_name);
43246  
43247                         buffer_copy_string_buffer(d.rel_path, dst->rel_path);
43248 -                       BUFFER_APPEND_SLASH(d.rel_path);
43249 +                       PATHNAME_APPEND_SLASH(d.rel_path);
43250                         buffer_append_string(d.rel_path, de->d_name);
43251  
43252                         if (-1 == stat(s.path->ptr, &st)) {
43253 @@ -692,19 +786,18 @@
43254                                                 sqlite3_reset(stmt);
43255  
43256                                                 /* bind the values to the insert */
43257 -                                               sqlite3_bind_text(stmt, 1, 
43258 -                                                         dst->rel_path->ptr, 
43259 +                                               sqlite3_bind_text(stmt, 1,
43260 +                                                         dst->rel_path->ptr,
43261                                                           dst->rel_path->used - 1,
43262                                                           SQLITE_TRANSIENT);
43263  
43264 -                                               sqlite3_bind_text(stmt, 2, 
43265 -                                                         src->rel_path->ptr, 
43266 +                                               sqlite3_bind_text(stmt, 2,
43267 +                                                         src->rel_path->ptr,
43268                                                           src->rel_path->used - 1,
43269                                                           SQLITE_TRANSIENT);
43270 -                                                                                                       
43271 +
43272                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
43273                                                         /* */
43274 -                                                       WP();
43275                                                 }
43276                                         }
43277  #endif
43278 @@ -721,7 +814,7 @@
43279                 buffer_free(s.rel_path);
43280                 buffer_free(d.path);
43281                 buffer_free(d.rel_path);
43282 -               
43283 +
43284                 closedir(srcdir);
43285         }
43286  
43287 @@ -748,12 +841,12 @@
43288                         if (S_ISDIR(sce->st.st_mode)) {
43289                                 buffer_append_string(b, "<D:getcontenttype>httpd/unix-directory</D:getcontenttype>");
43290                                 found = 1;
43291 -                       } else if(S_ISREG(sce->st.st_mode)) { 
43292 +                       } else if(S_ISREG(sce->st.st_mode)) {
43293                                 for (k = 0; k < con->conf.mimetypes->used; k++) {
43294                                         data_string *ds = (data_string *)con->conf.mimetypes->data[k];
43295 -               
43296 +
43297                                         if (ds->key->used == 0) continue;
43298 -                               
43299 +
43300                                         if (buffer_is_equal_right_len(dst->path, ds->key, ds->key->used - 1)) {
43301                                                 buffer_append_string(b,"<D:getcontenttype>");
43302                                                 buffer_append_string_buffer(b, ds->value);
43303 @@ -807,23 +900,23 @@
43304  
43305                         /* bind the values to the insert */
43306  
43307 -                       sqlite3_bind_text(stmt, 1, 
43308 -                                         dst->rel_path->ptr, 
43309 +                       sqlite3_bind_text(stmt, 1,
43310 +                                         dst->rel_path->ptr,
43311                                           dst->rel_path->used - 1,
43312                                           SQLITE_TRANSIENT);
43313 -                       sqlite3_bind_text(stmt, 2, 
43314 +                       sqlite3_bind_text(stmt, 2,
43315                                           prop_name,
43316                                           strlen(prop_name),
43317                                           SQLITE_TRANSIENT);
43318 -                       sqlite3_bind_text(stmt, 3, 
43319 +                       sqlite3_bind_text(stmt, 3,
43320                                           prop_ns,
43321                                           strlen(prop_ns),
43322                                           SQLITE_TRANSIENT);
43323  
43324                         /* it is the PK */
43325 -                       while (SQLITE_ROW == sqlite3_step(p->conf.stmt_select_prop)) {
43326 +                       while (SQLITE_ROW == sqlite3_step(stmt)) {
43327                                 /* there is a row for us, we only expect a single col 'value' */
43328 -                               webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(p->conf.stmt_select_prop, 0), b);
43329 +                               webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(stmt, 0), b);
43330                                 found = 1;
43331                         }
43332                 }
43333 @@ -840,7 +933,7 @@
43334         char *prop;
43335  } webdav_property;
43336  
43337 -webdav_property live_properties[] = { 
43338 +webdav_property live_properties[] = {
43339         { "DAV:", "creationdate" },
43340         { "DAV:", "displayname" },
43341         { "DAV:", "getcontentlanguage" },
43342 @@ -871,8 +964,8 @@
43343                         webdav_property *prop;
43344  
43345                         prop = props->ptr[i];
43346 -                       
43347 -                       if (0 != webdav_get_property(srv, con, p, 
43348 +
43349 +                       if (0 != webdav_get_property(srv, con, p,
43350                                 dst, prop->prop, prop->ns, b_200)) {
43351                                 webdav_gen_prop_tag(srv, con, prop->prop, prop->ns, NULL, b_404);
43352                         }
43353 @@ -916,12 +1009,12 @@
43354                                 if (-1 == c->file.fd &&  /* open the file if not already open */
43355                                     -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43356                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43357 -               
43358 +
43359                                         return -1;
43360                                 }
43361 -       
43362 +
43363                                 if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43364 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", 
43365 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
43366                                                         strerror(errno), c->file.name,  c->file.fd);
43367  
43368                                         return -1;
43369 @@ -938,7 +1031,7 @@
43370                         if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->file.mmap.start + c->offset, weHave, 0))) {
43371                                 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
43372                         }
43373 -                       
43374 +
43375                         c->offset += weHave;
43376                         cq->bytes_out += weHave;
43377  
43378 @@ -956,7 +1049,7 @@
43379                         if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->mem->ptr + c->offset, weHave, 0))) {
43380                                 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
43381                         }
43382 -                       
43383 +
43384                         c->offset += weHave;
43385                         cq->bytes_out += weHave;
43386  
43387 @@ -991,6 +1084,113 @@
43388  }
43389  #endif
43390  
43391 +int webdav_lockdiscovery(server *srv, connection *con,
43392 +               buffer *locktoken, const char *lockscope, const char *locktype, int depth) {
43393 +
43394 +       buffer *b;
43395 +
43396 +       response_header_overwrite(srv, con, CONST_STR_LEN("Lock-Token"), CONST_BUF_LEN(locktoken));
43397 +
43398 +       response_header_overwrite(srv, con,
43399 +               CONST_STR_LEN("Content-Type"),
43400 +               CONST_STR_LEN("text/xml; charset=\"utf-8\""));
43401 +
43402 +       b = chunkqueue_get_append_buffer(con->write_queue);
43403 +
43404 +       buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
43405 +
43406 +       buffer_append_string(b,"<D:prop xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
43407 +       buffer_append_string(b,"<D:lockdiscovery>\n");
43408 +       buffer_append_string(b,"<D:activelock>\n");
43409 +
43410 +       buffer_append_string(b,"<D:lockscope>");
43411 +       buffer_append_string(b,"<D:");
43412 +       buffer_append_string(b, lockscope);
43413 +       buffer_append_string(b, "/>");
43414 +       buffer_append_string(b,"</D:lockscope>\n");
43415 +
43416 +       buffer_append_string(b,"<D:locktype>");
43417 +       buffer_append_string(b,"<D:");
43418 +       buffer_append_string(b, locktype);
43419 +       buffer_append_string(b, "/>");
43420 +       buffer_append_string(b,"</D:locktype>\n");
43421 +
43422 +       buffer_append_string(b,"<D:depth>");
43423 +       buffer_append_string(b, depth == 0 ? "0" : "infinity");
43424 +       buffer_append_string(b,"</D:depth>\n");
43425 +
43426 +       buffer_append_string(b,"<D:timeout>");
43427 +       buffer_append_string(b, "Second-600");
43428 +       buffer_append_string(b,"</D:timeout>\n");
43429 +
43430 +       buffer_append_string(b,"<D:owner>");
43431 +       buffer_append_string(b,"</D:owner>\n");
43432 +
43433 +       buffer_append_string(b,"<D:locktoken>");
43434 +       buffer_append_string(b, "<D:href>");
43435 +       buffer_append_string_buffer(b, locktoken);
43436 +       buffer_append_string(b, "</D:href>");
43437 +       buffer_append_string(b,"</D:locktoken>\n");
43438 +
43439 +       buffer_append_string(b,"</D:activelock>\n");
43440 +       buffer_append_string(b,"</D:lockdiscovery>\n");
43441 +       buffer_append_string(b,"</D:prop>\n");
43442 +
43443 +       return 0;
43444 +}
43445 +/**
43446 + * check if resource is having the right locks to access to resource
43447 + *
43448 + *
43449 + *
43450 + */
43451 +int webdav_has_lock(server *srv, connection *con, plugin_data *p, buffer *uri) {
43452 +       int has_lock = 1;
43453 +
43454 +#ifdef USE_LOCKS
43455 +       data_string *ds;
43456 +
43457 +       /**
43458 +        * If can have
43459 +        * - <lock-token>
43460 +        * - [etag]
43461 +        *
43462 +        * there is NOT, AND and OR
43463 +        * and a list can be tagged
43464 +        *
43465 +        * (<lock-token>) is untagged
43466 +        * <tag> (<lock-token>) is tagged
43467 +        *
43468 +        * as long as we don't handle collections it is simple. :)
43469 +        *
43470 +        * X-Litmus: locks: 11 (owner_modify)
43471 +        * If: <http://127.0.0.1:1025/dav/litmus/lockme> (<opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1>)
43472 +        *
43473 +        * X-Litmus: locks: 16 (fail_cond_put)
43474 +        * If: (<DAV:no-lock> ["-1622396671"])
43475 +        */
43476 +       if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
43477 +       } else {
43478 +               /* we didn't provided a lock-token -> */
43479 +               /* if the resource is locked -> 423 */
43480 +
43481 +               sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
43482 +
43483 +               sqlite3_reset(stmt);
43484 +
43485 +               sqlite3_bind_text(stmt, 1,
43486 +                         CONST_BUF_LEN(uri),
43487 +                         SQLITE_TRANSIENT);
43488 +
43489 +               while (SQLITE_ROW == sqlite3_step(stmt)) {
43490 +                       has_lock = 0;
43491 +               }
43492 +       }
43493 +#endif
43494 +
43495 +       return has_lock;
43496 +}
43497 +
43498  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
43499         plugin_data *p = p_d;
43500         buffer *b;
43501 @@ -1001,7 +1201,8 @@
43502         buffer *prop_200;
43503         buffer *prop_404;
43504         webdav_properties *req_props;
43505 -       
43506 +       stat_cache_entry *sce = NULL;
43507 +
43508         UNUSED(srv);
43509  
43510         if (!p->conf.enabled) return HANDLER_GO_ON;
43511 @@ -1019,7 +1220,19 @@
43512                 req_props = NULL;
43513  
43514                 /* is there a content-body ? */
43515 -       
43516 +
43517 +               switch (stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
43518 +               case HANDLER_ERROR:
43519 +                       if (errno == ENOENT) {
43520 +                               con->http_status = 404;
43521 +                               return HANDLER_FINISHED;
43522 +                       }
43523 +                       break;
43524 +               default:
43525 +                       break;
43526 +               }
43527 +
43528 +
43529  #ifdef USE_PROPPATCH
43530                 /* any special requests or just allprop ? */
43531                 if (con->request.content_length) {
43532 @@ -1087,14 +1300,13 @@
43533                                                                 /* get all property names (EMPTY) */
43534                                                                 sqlite3_reset(stmt);
43535                                                                 /* bind the values to the insert */
43536 -       
43537 -                                                               sqlite3_bind_text(stmt, 1, 
43538 -                                                                                 con->uri.path->ptr, 
43539 +
43540 +                                                               sqlite3_bind_text(stmt, 1,
43541 +                                                                                 con->uri.path->ptr,
43542                                                                                   con->uri.path->used - 1,
43543                                                                                   SQLITE_TRANSIENT);
43544 -                                               
43545 +
43546                                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
43547 -                                                                       WP();
43548                                                                 }
43549                                                         }
43550                                                 } else if (0 == xmlStrcmp(cmd->name, BAD_CAST "allprop")) {
43551 @@ -1115,13 +1327,13 @@
43552                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
43553  
43554                 b = chunkqueue_get_append_buffer(con->write_queue);
43555 -                               
43556 +
43557                 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
43558  
43559                 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
43560  
43561                 /* allprop */
43562 -               
43563 +
43564                 prop_200 = buffer_init();
43565                 prop_404 = buffer_init();
43566  
43567 @@ -1129,7 +1341,7 @@
43568                 case 0:
43569                         /* Depth: 0 */
43570                         webdav_get_props(srv, con, p, &(con->physical), req_props, prop_200, prop_404);
43571 -       
43572 +
43573                         buffer_append_string(b,"<D:response>\n");
43574                         buffer_append_string(b,"<D:href>");
43575                         buffer_append_string_buffer(b, con->uri.scheme);
43576 @@ -1145,9 +1357,9 @@
43577                                 buffer_append_string_buffer(b, prop_200);
43578  
43579                                 buffer_append_string(b,"</D:prop>\n");
43580 -       
43581 +
43582                                 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
43583 -       
43584 +
43585                                 buffer_append_string(b,"</D:propstat>\n");
43586                         }
43587                         if (!buffer_is_empty(prop_404)) {
43588 @@ -1157,16 +1369,16 @@
43589                                 buffer_append_string_buffer(b, prop_404);
43590  
43591                                 buffer_append_string(b,"</D:prop>\n");
43592 -       
43593 +
43594                                 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
43595 -       
43596 +
43597                                 buffer_append_string(b,"</D:propstat>\n");
43598                         }
43599  
43600                         buffer_append_string(b,"</D:response>\n");
43601  
43602                         break;
43603 -               case 1: 
43604 +               case 1:
43605                         if (NULL != (dir = opendir(con->physical.path->ptr))) {
43606                                 struct dirent *de;
43607                                 physical d;
43608 @@ -1179,16 +1391,16 @@
43609                                         if (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0') {
43610                                                 continue;
43611                                                 /* ignore the parent dir */
43612 -                                       } 
43613 +                                       }
43614  
43615                                         buffer_copy_string_buffer(d.path, dst->path);
43616 -                                       BUFFER_APPEND_SLASH(d.path);
43617 +                                       PATHNAME_APPEND_SLASH(d.path);
43618  
43619                                         buffer_copy_string_buffer(d.rel_path, dst->rel_path);
43620 -                                       BUFFER_APPEND_SLASH(d.rel_path);
43621 +                                       PATHNAME_APPEND_SLASH(d.rel_path);
43622  
43623                                         if (de->d_name[0] == '.' && de->d_name[1] == '\0') {
43624 -                                               /* don't append the . */ 
43625 +                                               /* don't append the . */
43626                                         } else {
43627                                                 buffer_append_string(d.path, de->d_name);
43628                                                 buffer_append_string(d.rel_path, de->d_name);
43629 @@ -1198,7 +1410,7 @@
43630                                         buffer_reset(prop_404);
43631  
43632                                         webdav_get_props(srv, con, p, &d, req_props, prop_200, prop_404);
43633 -                                       
43634 +
43635                                         buffer_append_string(b,"<D:response>\n");
43636                                         buffer_append_string(b,"<D:href>");
43637                                         buffer_append_string_buffer(b, con->uri.scheme);
43638 @@ -1214,9 +1426,9 @@
43639                                                 buffer_append_string_buffer(b, prop_200);
43640  
43641                                                 buffer_append_string(b,"</D:prop>\n");
43642 -                       
43643 +
43644                                                 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
43645 -                       
43646 +
43647                                                 buffer_append_string(b,"</D:propstat>\n");
43648                                         }
43649                                         if (!buffer_is_empty(prop_404)) {
43650 @@ -1226,9 +1438,9 @@
43651                                                 buffer_append_string_buffer(b, prop_404);
43652  
43653                                                 buffer_append_string(b,"</D:prop>\n");
43654 -       
43655 +
43656                                                 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
43657 -       
43658 +
43659                                                 buffer_append_string(b,"</D:propstat>\n");
43660                                         }
43661  
43662 @@ -1275,7 +1487,7 @@
43663  
43664                         return HANDLER_FINISHED;
43665                 }
43666 -       
43667 +
43668                 /* let's create the directory */
43669  
43670                 if (-1 == mkdir(con->physical.path->ptr, 0700)) {
43671 @@ -1303,7 +1515,13 @@
43672                         con->http_status = 403;
43673                         return HANDLER_FINISHED;
43674                 }
43675 -               
43676 +
43677 +               /* does the client have a lock for this connection ? */
43678 +               if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43679 +                       con->http_status = 423;
43680 +                       return HANDLER_FINISHED;
43681 +               }
43682 +
43683                 /* stat and unlink afterwards */
43684                 if (-1 == stat(con->physical.path->ptr, &st)) {
43685                         /* don't about it yet, unlink will fail too */
43686 @@ -1323,7 +1541,7 @@
43687                                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
43688  
43689                                 b = chunkqueue_get_append_buffer(con->write_queue);
43690 -                       
43691 +
43692                                 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
43693  
43694                                 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\">\n");
43695 @@ -1331,7 +1549,7 @@
43696                                 buffer_append_string_buffer(b, multi_status_resp);
43697  
43698                                 buffer_append_string(b,"</D:multistatus>\n");
43699 -                       
43700 +
43701                                 if (p->conf.log_xml) {
43702                                         log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
43703                                 }
43704 @@ -1340,7 +1558,7 @@
43705                                 con->file_finished = 1;
43706                         } else {
43707                                 /* everything went fine, remove the directory */
43708 -       
43709 +
43710                                 if (-1 == rmdir(con->physical.path->ptr)) {
43711                                         switch(errno) {
43712                                         case ENOENT:
43713 @@ -1375,97 +1593,174 @@
43714         case HTTP_METHOD_PUT: {
43715                 int fd;
43716                 chunkqueue *cq = con->request_content_queue;
43717 +               chunk *c;
43718 +               data_string *ds_range;
43719  
43720                 if (p->conf.is_readonly) {
43721                         con->http_status = 403;
43722                         return HANDLER_FINISHED;
43723                 }
43724  
43725 +               /* is a exclusive lock set on the source */
43726 +               if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43727 +                       con->http_status = 423;
43728 +                       return HANDLER_FINISHED;
43729 +               }
43730 +
43731 +
43732                 assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
43733  
43734 -               /* taken what we have in the request-body and write it to a file */
43735 -               if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC, 0600))) {
43736 -                       /* we can't open the file */
43737 -                       con->http_status = 403;
43738 -               } else {
43739 -                       chunk *c;
43740 +               /* RFC2616 Section 9.6 PUT requires us to send 501 on all Content-* we don't support
43741 +                * - most important Content-Range
43742 +                *
43743 +                *
43744 +                * Example: Content-Range: bytes 100-1037/1038 */
43745  
43746 -                       con->http_status = 201; /* created */
43747 -                       con->file_finished = 1;
43748 +               if (NULL != (ds_range = (data_string *)array_get_element(con->request.headers, "Content-Range"))) {
43749 +                       const char *num = ds_range->value->ptr;
43750 +                       off_t offset;
43751 +                       char *err = NULL;
43752  
43753 -                       for (c = cq->first; c; c = cq->first) {
43754 -                               int r = 0; 
43755 +                       if (0 != strncmp(num, "bytes ", 6)) {
43756 +                               con->http_status = 501; /* not implemented */
43757  
43758 -                               /* copy all chunks */
43759 -                               switch(c->type) {
43760 -                               case FILE_CHUNK:
43761 -
43762 -                                       if (c->file.mmap.start == MAP_FAILED) {
43763 -                                               if (-1 == c->file.fd &&  /* open the file if not already open */
43764 -                                                   -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43765 -                                                       log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43766 -                                       
43767 -                                                       return -1;
43768 -                                               }
43769 -                               
43770 -                                               if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43771 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", 
43772 -                                                                       strerror(errno), c->file.name,  c->file.fd);
43773 +                               return HANDLER_FINISHED;
43774 +                       }
43775  
43776 -                                                       return -1;
43777 -                                               }
43778 +                       /* we only support <num>- ... */
43779  
43780 -                                               c->file.mmap.length = c->file.length;
43781 +                       num += 6;
43782  
43783 -                                               close(c->file.fd);
43784 -                                               c->file.fd = -1;
43785 -       
43786 -                                               /* chunk_reset() or chunk_free() will cleanup for us */
43787 -                                       }
43788 -
43789 -                                       if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
43790 -                                               switch(errno) {
43791 -                                               case ENOSPC:
43792 -                                                       con->http_status = 507;
43793 -               
43794 -                                                       break;
43795 -                                               default:
43796 -                                                       con->http_status = 403;
43797 -                                                       break;
43798 -                                               }
43799 -                                       }
43800 -                                       break;
43801 -                               case MEM_CHUNK:
43802 -                                       if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
43803 -                                               switch(errno) {
43804 -                                               case ENOSPC:
43805 -                                                       con->http_status = 507;
43806 -               
43807 -                                                       break;
43808 -                                               default:
43809 -                                                       con->http_status = 403;
43810 -                                                       break;
43811 -                                               }
43812 -                                       }
43813 +                       /* skip WS */
43814 +                       while (*num == ' ' || *num == '\t') num++;
43815 +
43816 +                       if (*num == '\0') {
43817 +                               con->http_status = 501; /* not implemented */
43818 +
43819 +                               return HANDLER_FINISHED;
43820 +                       }
43821 +
43822 +                       offset = strtoll(num, &err, 10);
43823 +
43824 +                       if (*err != '-' || offset < 0) {
43825 +                               con->http_status = 501; /* not implemented */
43826 +
43827 +                               return HANDLER_FINISHED;
43828 +                       }
43829 +
43830 +                       if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, 0600))) {
43831 +                               switch (errno) {
43832 +                               case ENOENT:
43833 +                                       con->http_status = 404; /* not found */
43834                                         break;
43835 -                               case UNUSED_CHUNK:
43836 +                               default:
43837 +                                       con->http_status = 403; /* not found */
43838                                         break;
43839                                 }
43840 +                               return HANDLER_FINISHED;
43841 +                       }
43842 +
43843 +                       if (-1 == lseek(fd, offset, SEEK_SET)) {
43844 +                               con->http_status = 501; /* not implemented */
43845 +
43846 +                               close(fd);
43847 +
43848 +                               return HANDLER_FINISHED;
43849 +                       }
43850 +                       con->http_status = 200; /* modified */
43851 +               } else {
43852 +                       /* take what we have in the request-body and write it to a file */
43853 +
43854 +                       /* if the file doesn't exist, create it */
43855 +                       if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, 0600))) {
43856 +                               if (errno == ENOENT &&
43857 +                                   -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0600))) {
43858 +                                       /* we can't open the file */
43859 +                                       con->http_status = 403;
43860  
43861 -                               if (r > 0) {
43862 -                                       c->offset += r;
43863 -                                       cq->bytes_out += r;
43864 +                                       return HANDLER_FINISHED;
43865                                 } else {
43866 -                                       break;
43867 +                                       con->http_status = 201; /* created */
43868 +                               }
43869 +                       } else {
43870 +                               con->http_status = 200; /* modified */
43871 +                       }
43872 +               }
43873 +
43874 +               con->file_finished = 1;
43875 +
43876 +               for (c = cq->first; c; c = cq->first) {
43877 +                       int r = 0;
43878 +
43879 +                       /* copy all chunks */
43880 +                       switch(c->type) {
43881 +                       case FILE_CHUNK:
43882 +
43883 +                               if (c->file.mmap.start == MAP_FAILED) {
43884 +                                       if (-1 == c->file.fd &&  /* open the file if not already open */
43885 +                                           -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43886 +                                               log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43887 +
43888 +                                               return -1;
43889 +                                       }
43890 +
43891 +                                       if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43892 +                                               log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
43893 +                                                               strerror(errno), c->file.name,  c->file.fd);
43894 +
43895 +                                               return -1;
43896 +                                       }
43897 +
43898 +                                       c->file.mmap.length = c->file.length;
43899 +
43900 +                                       close(c->file.fd);
43901 +                                       c->file.fd = -1;
43902 +
43903 +                                       /* chunk_reset() or chunk_free() will cleanup for us */
43904 +                               }
43905 +
43906 +                               if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
43907 +                                       switch(errno) {
43908 +                                       case ENOSPC:
43909 +                                               con->http_status = 507;
43910 +
43911 +                                               break;
43912 +                                       default:
43913 +                                               con->http_status = 403;
43914 +                                               break;
43915 +                                       }
43916                                 }
43917 -                               chunkqueue_remove_finished_chunks(cq);
43918 +                               break;
43919 +                       case MEM_CHUNK:
43920 +                               if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
43921 +                                       switch(errno) {
43922 +                                       case ENOSPC:
43923 +                                               con->http_status = 507;
43924 +
43925 +                                               break;
43926 +                                       default:
43927 +                                               con->http_status = 403;
43928 +                                               break;
43929 +                                       }
43930 +                               }
43931 +                               break;
43932 +                       case UNUSED_CHUNK:
43933 +                               break;
43934                         }
43935 -                       close(fd);
43936  
43937 +                       if (r > 0) {
43938 +                               c->offset += r;
43939 +                               cq->bytes_out += r;
43940 +                       } else {
43941 +                               break;
43942 +                       }
43943 +                       chunkqueue_remove_finished_chunks(cq);
43944                 }
43945 +               close(fd);
43946 +
43947                 return HANDLER_FINISHED;
43948         }
43949 -       case HTTP_METHOD_MOVE: 
43950 +       case HTTP_METHOD_MOVE:
43951         case HTTP_METHOD_COPY: {
43952                 buffer *destination = NULL;
43953                 char *sep, *start;
43954 @@ -1475,7 +1770,15 @@
43955                         con->http_status = 403;
43956                         return HANDLER_FINISHED;
43957                 }
43958 -               
43959 +
43960 +               /* is a exclusive lock set on the source */
43961 +               if (con->request.http_method == HTTP_METHOD_MOVE) {
43962 +                       if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43963 +                               con->http_status = 423;
43964 +                               return HANDLER_FINISHED;
43965 +                       }
43966 +               }
43967 +
43968                 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Destination"))) {
43969                         destination = ds->value;
43970                 } else {
43971 @@ -1549,10 +1852,10 @@
43972                 }
43973  
43974                 buffer_copy_string_buffer(p->physical.path, p->physical.doc_root);
43975 -               BUFFER_APPEND_SLASH(p->physical.path);
43976 +               PATHNAME_APPEND_SLASH(p->physical.path);
43977                 buffer_copy_string_buffer(p->physical.basedir, p->physical.path);
43978  
43979 -               /* don't add a second / */ 
43980 +               /* don't add a second / */
43981                 if (p->physical.rel_path->ptr[0] == '/') {
43982                         buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr + 1, p->physical.rel_path->used - 2);
43983                 } else {
43984 @@ -1613,6 +1916,12 @@
43985                         /* it is just a file, good */
43986                         int r;
43987  
43988 +                       /* does the client have a lock for this connection ? */
43989 +                       if (!webdav_has_lock(srv, con, p, p->uri.path)) {
43990 +                               con->http_status = 423;
43991 +                               return HANDLER_FINISHED;
43992 +                       }
43993 +
43994                         /* destination exists */
43995                         if (0 == (r = stat(p->physical.path->ptr, &st))) {
43996                                 if (S_ISDIR(st.st_mode)) {
43997 @@ -1636,7 +1945,7 @@
43998                                         return HANDLER_FINISHED;
43999                                 }
44000                         } else if (overwrite == 0) {
44001 -                               /* destination exists, but overwrite is not set */ 
44002 +                               /* destination exists, but overwrite is not set */
44003                                 con->http_status = 412;
44004                                 return HANDLER_FINISHED;
44005                         } else {
44006 @@ -1655,16 +1964,16 @@
44007                                                 sqlite3_reset(stmt);
44008  
44009                                                 /* bind the values to the insert */
44010 -                                               sqlite3_bind_text(stmt, 1, 
44011 -                                                                 p->uri.path->ptr, 
44012 +                                               sqlite3_bind_text(stmt, 1,
44013 +                                                                 p->uri.path->ptr,
44014                                                                   p->uri.path->used - 1,
44015                                                                   SQLITE_TRANSIENT);
44016  
44017 -                                               sqlite3_bind_text(stmt, 2, 
44018 -                                                                 con->uri.path->ptr, 
44019 +                                               sqlite3_bind_text(stmt, 2,
44020 +                                                                 con->uri.path->ptr,
44021                                                                   con->uri.path->used - 1,
44022                                                                   SQLITE_TRANSIENT);
44023 -                                               
44024 +
44025                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
44026                                                         log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move failed:", sqlite3_errmsg(p->conf.sql));
44027                                                 }
44028 @@ -1691,12 +2000,17 @@
44029  
44030                 return HANDLER_FINISHED;
44031         }
44032 -       case HTTP_METHOD_PROPPATCH: {
44033 +       case HTTP_METHOD_PROPPATCH:
44034                 if (p->conf.is_readonly) {
44035                         con->http_status = 403;
44036                         return HANDLER_FINISHED;
44037                 }
44038  
44039 +               if (!webdav_has_lock(srv, con, p, con->uri.path)) {
44040 +                       con->http_status = 423;
44041 +                       return HANDLER_FINISHED;
44042 +               }
44043 +
44044                 /* check if destination exists */
44045                 if (-1 == stat(con->physical.path->ptr, &st)) {
44046                         switch(errno) {
44047 @@ -1737,7 +2051,7 @@
44048  
44049                                                         sqlite3_stmt *stmt;
44050  
44051 -                                                       stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ? 
44052 +                                                       stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ?
44053                                                                 p->conf.stmt_delete_prop : p->conf.stmt_update_prop;
44054  
44055                                                         for (props = cmd->children; props; props = props->next) {
44056 @@ -1762,34 +2076,35 @@
44057  
44058                                                                         /* bind the values to the insert */
44059  
44060 -                                                                       sqlite3_bind_text(stmt, 1, 
44061 -                                                                                         con->uri.path->ptr, 
44062 +                                                                       sqlite3_bind_text(stmt, 1,
44063 +                                                                                         con->uri.path->ptr,
44064                                                                                           con->uri.path->used - 1,
44065                                                                                           SQLITE_TRANSIENT);
44066 -                                                                       sqlite3_bind_text(stmt, 2, 
44067 +                                                                       sqlite3_bind_text(stmt, 2,
44068                                                                                           (char *)prop->name,
44069                                                                                           strlen((char *)prop->name),
44070                                                                                           SQLITE_TRANSIENT);
44071                                                                         if (prop->ns) {
44072 -                                                                               sqlite3_bind_text(stmt, 3, 
44073 +                                                                               sqlite3_bind_text(stmt, 3,
44074                                                                                                   (char *)prop->ns->href,
44075                                                                                                   strlen((char *)prop->ns->href),
44076                                                                                                   SQLITE_TRANSIENT);
44077                                                                         } else {
44078 -                                                                               sqlite3_bind_text(stmt, 3, 
44079 +                                                                               sqlite3_bind_text(stmt, 3,
44080                                                                                                   "",
44081                                                                                                   0,
44082                                                                                                   SQLITE_TRANSIENT);
44083                                                                         }
44084                                                                         if (stmt == p->conf.stmt_update_prop) {
44085 -                                                                               sqlite3_bind_text(stmt, 4, 
44086 +                                                                               sqlite3_bind_text(stmt, 4,
44087                                                                                           (char *)xmlNodeGetContent(prop),
44088                                                                                           strlen((char *)xmlNodeGetContent(prop)),
44089                                                                                           SQLITE_TRANSIENT);
44090                                                                         }
44091 -                                                               
44092 +
44093                                                                         if (SQLITE_DONE != (r = sqlite3_step(stmt))) {
44094 -                                                                               log_error_write(srv, __FILE__, __LINE__, "ss", "sql-set failed:", sqlite3_errmsg(p->conf.sql));
44095 +                                                                               log_error_write(srv, __FILE__, __LINE__, "ss",
44096 +                                                                                               "sql-set failed:", sqlite3_errmsg(p->conf.sql));
44097                                                                         }
44098                                                                 }
44099                                                         }
44100 @@ -1804,7 +2119,7 @@
44101  
44102                                                         goto propmatch_cleanup;
44103                                                 }
44104 -       
44105 +
44106                                                 con->http_status = 400;
44107                                         } else {
44108                                                 if (SQLITE_OK != sqlite3_exec(p->conf.sql, "COMMIT", NULL, NULL, &err)) {
44109 @@ -1821,6 +2136,7 @@
44110                                 }
44111  
44112  propmatch_cleanup:
44113 +
44114                                 xmlFreeDoc(xml);
44115                         } else {
44116                                 con->http_status = 400;
44117 @@ -1830,11 +2146,307 @@
44118  #endif
44119                 con->http_status = 501;
44120                 return HANDLER_FINISHED;
44121 -       }
44122 +       case HTTP_METHOD_LOCK:
44123 +               /**
44124 +                * a mac wants to write
44125 +                *
44126 +                * LOCK /dav/expire.txt HTTP/1.1\r\n
44127 +                * User-Agent: WebDAVFS/1.3 (01308000) Darwin/8.1.0 (Power Macintosh)\r\n
44128 +                * Accept: * / *\r\n
44129 +                * Depth: 0\r\n
44130 +                * Timeout: Second-600\r\n
44131 +                * Content-Type: text/xml; charset=\"utf-8\"\r\n
44132 +                * Content-Length: 229\r\n
44133 +                * Connection: keep-alive\r\n
44134 +                * Host: 192.168.178.23:1025\r\n
44135 +                * \r\n
44136 +                * <?xml version=\"1.0\" encoding=\"utf-8\"?>\n
44137 +                * <D:lockinfo xmlns:D=\"DAV:\">\n
44138 +                *  <D:lockscope><D:exclusive/></D:lockscope>\n
44139 +                *  <D:locktype><D:write/></D:locktype>\n
44140 +                *  <D:owner>\n
44141 +                *   <D:href>http://www.apple.com/webdav_fs/</D:href>\n
44142 +                *  </D:owner>\n
44143 +                * </D:lockinfo>\n
44144 +                */
44145 +
44146 +               if (depth != 0 && depth != -1) {
44147 +                       con->http_status = 400;
44148 +
44149 +                       return HANDLER_FINISHED;
44150 +               }
44151 +
44152 +#ifdef USE_LOCKS
44153 +               if (con->request.content_length) {
44154 +                       xmlDocPtr xml;
44155 +                       buffer *hdr_if = NULL;
44156 +
44157 +                       if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
44158 +                               hdr_if = ds->value;
44159 +                       }
44160 +
44161 +                       /* we don't support Depth: Infinity on locks */
44162 +                       if (hdr_if == NULL && depth == -1) {
44163 +                               con->http_status = 409; /* Conflict */
44164 +
44165 +                               return HANDLER_FINISHED;
44166 +                       }
44167 +
44168 +                       if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
44169 +                               xmlNode *rootnode = xmlDocGetRootElement(xml);
44170 +
44171 +                               assert(rootnode);
44172 +
44173 +                               if (0 == xmlStrcmp(rootnode->name, BAD_CAST "lockinfo")) {
44174 +                                       xmlNode *lockinfo;
44175 +                                       const xmlChar *lockscope = NULL, *locktype = NULL, *owner = NULL;
44176 +
44177 +                                       for (lockinfo = rootnode->children; lockinfo; lockinfo = lockinfo->next) {
44178 +                                               if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "lockscope")) {
44179 +                                                       xmlNode *value;
44180 +                                                       for (value = lockinfo->children; value; value = value->next) {
44181 +                                                               if ((0 == xmlStrcmp(value->name, BAD_CAST "exclusive")) ||
44182 +                                                                   (0 == xmlStrcmp(value->name, BAD_CAST "shared"))) {
44183 +                                                                       lockscope = value->name;
44184 +                                                               } else {
44185 +                                                                       con->http_status = 400;
44186 +
44187 +                                                                       xmlFreeDoc(xml);
44188 +                                                                       return HANDLER_FINISHED;
44189 +                                                               }
44190 +                                                       }
44191 +                                               } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "locktype")) {
44192 +                                                       xmlNode *value;
44193 +                                                       for (value = lockinfo->children; value; value = value->next) {
44194 +                                                               if ((0 == xmlStrcmp(value->name, BAD_CAST "write"))) {
44195 +                                                                       locktype = value->name;
44196 +                                                               } else {
44197 +                                                                       con->http_status = 400;
44198 +
44199 +                                                                       xmlFreeDoc(xml);
44200 +                                                                       return HANDLER_FINISHED;
44201 +                                                               }
44202 +                                                       }
44203 +
44204 +                                               } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "owner")) {
44205 +                                               }
44206 +                                       }
44207 +
44208 +                                       if (lockscope && locktype) {
44209 +                                               sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
44210 +
44211 +                                               /* is this resourse already locked ? */
44212 +
44213 +                                               /* SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout
44214 +                                                *   FROM locks
44215 +                                                *  WHERE resource = ? */
44216 +
44217 +                                               if (stmt) {
44218 +
44219 +                                                       sqlite3_reset(stmt);
44220 +
44221 +                                                       sqlite3_bind_text(stmt, 1,
44222 +                                                                         p->uri.path->ptr,
44223 +                                                                         p->uri.path->used - 1,
44224 +                                                                         SQLITE_TRANSIENT);
44225 +
44226 +                                                       /* it is the PK */
44227 +                                                       while (SQLITE_ROW == sqlite3_step(stmt)) {
44228 +                                                               /* we found a lock
44229 +                                                                * 1. is it compatible ?
44230 +                                                                * 2. is it ours */
44231 +                                                               char *sql_lockscope = (char *)sqlite3_column_text(stmt, 2);
44232 +
44233 +                                                               if (strcmp(sql_lockscope, "exclusive")) {
44234 +                                                                       con->http_status = 423;
44235 +                                                               } else if (0 == xmlStrcmp(lockscope, BAD_CAST "exclusive")) {
44236 +                                                                       /* resourse is locked with a shared lock
44237 +                                                                        * client wants exclusive */
44238 +                                                                       con->http_status = 423;
44239 +                                                               }
44240 +                                                       }
44241 +                                                       if (con->http_status == 423) {
44242 +                                                               xmlFreeDoc(xml);
44243 +                                                               return HANDLER_FINISHED;
44244 +                                                       }
44245 +                                               }
44246 +
44247 +                                               stmt = p->conf.stmt_create_lock;
44248 +                                               if (stmt) {
44249 +                                                       /* create a lock-token */
44250 +                                                       uuid_t id;
44251 +                                                       char uuid[37] /* 36 + \0 */;
44252 +
44253 +                                                       uuid_generate(id);
44254 +                                                       uuid_unparse(id, uuid);
44255 +
44256 +                                                       buffer_copy_string(p->tmp_buf, "opaquelocktoken:");
44257 +                                                       buffer_append_string(p->tmp_buf, uuid);
44258 +
44259 +                                                       /* "CREATE TABLE locks ("
44260 +                                                        * "  locktoken TEXT NOT NULL,"
44261 +                                                        * "  resource TEXT NOT NULL,"
44262 +                                                        * "  lockscope TEXT NOT NULL,"
44263 +                                                        * "  locktype TEXT NOT NULL,"
44264 +                                                        * "  owner TEXT NOT NULL,"
44265 +                                                        * "  depth INT NOT NULL,"
44266 +                                                        */
44267 +
44268 +                                                       sqlite3_reset(stmt);
44269 +
44270 +                                                       sqlite3_bind_text(stmt, 1,
44271 +                                                                         CONST_BUF_LEN(p->tmp_buf),
44272 +                                                                         SQLITE_TRANSIENT);
44273 +
44274 +                                                       sqlite3_bind_text(stmt, 2,
44275 +                                                                         CONST_BUF_LEN(con->uri.path),
44276 +                                                                         SQLITE_TRANSIENT);
44277 +
44278 +                                                       sqlite3_bind_text(stmt, 3,
44279 +                                                                         lockscope,
44280 +                                                                         xmlStrlen(lockscope),
44281 +                                                                         SQLITE_TRANSIENT);
44282 +
44283 +                                                       sqlite3_bind_text(stmt, 4,
44284 +                                                                         locktype,
44285 +                                                                         xmlStrlen(locktype),
44286 +                                                                         SQLITE_TRANSIENT);
44287 +
44288 +                                                       /* owner */
44289 +                                                       sqlite3_bind_text(stmt, 5,
44290 +                                                                         "",
44291 +                                                                         0,
44292 +                                                                         SQLITE_TRANSIENT);
44293 +
44294 +                                                       /* depth */
44295 +                                                       sqlite3_bind_int(stmt, 6,
44296 +                                                                        depth);
44297 +
44298 +
44299 +                                                       if (SQLITE_DONE != sqlite3_step(stmt)) {
44300 +                                                               log_error_write(srv, __FILE__, __LINE__, "ss",
44301 +                                                                               "create lock:", sqlite3_errmsg(p->conf.sql));
44302 +                                                       }
44303 +
44304 +                                                       /* looks like we survived */
44305 +                                                       webdav_lockdiscovery(srv, con, p->tmp_buf, lockscope, locktype, depth);
44306 +
44307 +                                                       con->http_status = 201;
44308 +                                                       con->file_finished = 1;
44309 +                                               }
44310 +                                       }
44311 +                               }
44312 +
44313 +                               xmlFreeDoc(xml);
44314 +                               return HANDLER_FINISHED;
44315 +                       } else {
44316 +                               con->http_status = 400;
44317 +                               return HANDLER_FINISHED;
44318 +                       }
44319 +               } else {
44320 +
44321 +                       if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
44322 +                               buffer *locktoken = ds->value;
44323 +                               sqlite3_stmt *stmt = p->conf.stmt_refresh_lock;
44324 +
44325 +                               /* remove the < > around the token */
44326 +                               if (locktoken->used < 6) {
44327 +                                       con->http_status = 400;
44328 +
44329 +                                       return HANDLER_FINISHED;
44330 +                               }
44331 +
44332 +                               buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 2, locktoken->used - 5);
44333 +
44334 +                               sqlite3_reset(stmt);
44335 +
44336 +                               sqlite3_bind_text(stmt, 1,
44337 +                                         CONST_BUF_LEN(p->tmp_buf),
44338 +                                         SQLITE_TRANSIENT);
44339 +
44340 +                               if (SQLITE_DONE != sqlite3_step(stmt)) {
44341 +                                       log_error_write(srv, __FILE__, __LINE__, "ss",
44342 +                                               "refresh lock:", sqlite3_errmsg(p->conf.sql));
44343 +                               }
44344 +
44345 +                               webdav_lockdiscovery(srv, con, p->tmp_buf, "exclusive", "write", 0);
44346 +
44347 +                               con->http_status = 200;
44348 +                               con->file_finished = 1;
44349 +                               return HANDLER_FINISHED;
44350 +                       } else {
44351 +                               /* we need a lock-token to refresh */
44352 +                               con->http_status = 400;
44353 +
44354 +                               return HANDLER_FINISHED;
44355 +                       }
44356 +               }
44357 +               break;
44358 +#else
44359 +               con->http_status = 501;
44360 +               return HANDLER_FINISHED;
44361 +#endif
44362 +       case HTTP_METHOD_UNLOCK:
44363 +#ifdef USE_LOCKS
44364 +               if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Lock-Token"))) {
44365 +                       buffer *locktoken = ds->value;
44366 +                       sqlite3_stmt *stmt = p->conf.stmt_remove_lock;
44367 +
44368 +                       /* remove the < > around the token */
44369 +                       if (locktoken->used < 4) {
44370 +                               con->http_status = 400;
44371 +
44372 +                               return HANDLER_FINISHED;
44373 +                       }
44374 +
44375 +                       /**
44376 +                        * FIXME:
44377 +                        *
44378 +                        * if the resourse is locked:
44379 +                        * - by us: unlock
44380 +                        * - by someone else: 401
44381 +                        * if the resource is not locked:
44382 +                        * - 412
44383 +                        *  */
44384 +
44385 +                       buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 1, locktoken->used - 3);
44386 +
44387 +                       sqlite3_reset(stmt);
44388 +
44389 +                       sqlite3_bind_text(stmt, 1,
44390 +                                 CONST_BUF_LEN(p->tmp_buf),
44391 +                                 SQLITE_TRANSIENT);
44392 +
44393 +                       sqlite3_bind_text(stmt, 2,
44394 +                                 CONST_BUF_LEN(con->uri.path),
44395 +                                 SQLITE_TRANSIENT);
44396 +
44397 +                       if (SQLITE_DONE != sqlite3_step(stmt)) {
44398 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
44399 +                                       "remove lock:", sqlite3_errmsg(p->conf.sql));
44400 +                       }
44401 +
44402 +                       if (0 == sqlite3_changes(p->conf.sql)) {
44403 +                               con->http_status = 401;
44404 +                       } else {
44405 +                               con->http_status = 204;
44406 +                       }
44407 +                       return HANDLER_FINISHED;
44408 +               } else {
44409 +                       /* we need a lock-token to unlock */
44410 +                       con->http_status = 400;
44411 +
44412 +                       return HANDLER_FINISHED;
44413 +               }
44414 +               break;
44415 +#else
44416 +               con->http_status = 501;
44417 +               return HANDLER_FINISHED;
44418 +#endif
44419         default:
44420                 break;
44421         }
44422 -       
44423 +
44424         /* not found */
44425         return HANDLER_GO_ON;
44426  }
44427 @@ -1845,14 +2457,14 @@
44428  int mod_webdav_plugin_init(plugin *p) {
44429         p->version     = LIGHTTPD_VERSION_ID;
44430         p->name        = buffer_init_string("webdav");
44431 -       
44432 +
44433         p->init        = mod_webdav_init;
44434         p->handle_uri_clean  = mod_webdav_uri_handler;
44435         p->handle_physical   = mod_webdav_subrequest_handler;
44436         p->set_defaults  = mod_webdav_set_defaults;
44437         p->cleanup     = mod_webdav_free;
44438 -       
44439 +
44440         p->data        = NULL;
44441 -       
44442 +
44443         return 0;
44444  }
44445 --- ../lighttpd-1.4.11/src/network.c    2006-03-04 16:45:46.000000000 +0200
44446 +++ lighttpd-1.4.12/src/network.c       2006-07-18 13:03:40.000000000 +0300
44447 @@ -1,14 +1,14 @@
44448  #include <sys/types.h>
44449  #include <sys/stat.h>
44450 -#include <sys/time.h>
44451  
44452  #include <errno.h>
44453  #include <fcntl.h>
44454 -#include <unistd.h>
44455  #include <string.h>
44456  #include <stdlib.h>
44457  #include <assert.h>
44458  
44459 +#include <stdio.h>
44460 +
44461  #include "network.h"
44462  #include "fdevent.h"
44463  #include "log.h"
44464 @@ -19,11 +19,12 @@
44465  #include "network_backends.h"
44466  #include "sys-mmap.h"
44467  #include "sys-socket.h"
44468 +#include "sys-files.h"
44469  
44470  #ifdef USE_OPENSSL
44471 -# include <openssl/ssl.h> 
44472 -# include <openssl/err.h> 
44473 -# include <openssl/rand.h> 
44474 +# include <openssl/ssl.h>
44475 +# include <openssl/err.h>
44476 +# include <openssl/rand.h>
44477  #endif
44478  
44479  handler_t network_server_handle_fdevent(void *s, void *context, int revents) {
44480 @@ -31,25 +32,25 @@
44481         server_socket *srv_socket = (server_socket *)context;
44482         connection *con;
44483         int loops = 0;
44484 -       
44485 +
44486         UNUSED(context);
44487 -       
44488 +
44489         if (revents != FDEVENT_IN) {
44490 -               log_error_write(srv, __FILE__, __LINE__, "sdd", 
44491 +               log_error_write(srv, __FILE__, __LINE__, "sdd",
44492                                 "strange event for server socket",
44493 -                               srv_socket->fd,
44494 +                               srv_socket->sock->fd,
44495                                 revents);
44496                 return HANDLER_ERROR;
44497         }
44498  
44499         /* accept()s at most 100 connections directly
44500          *
44501 -        * we jump out after 100 to give the waiting connections a chance */    
44502 +        * we jump out after 100 to give the waiting connections a chance */
44503         for (loops = 0; loops < 100 && NULL != (con = connection_accept(srv, srv_socket)); loops++) {
44504                 handler_t r;
44505 -               
44506 +
44507                 connection_state_machine(srv, con);
44508 -               
44509 +
44510                 switch(r = plugins_call_handle_joblist(srv, con)) {
44511                 case HANDLER_FINISHED:
44512                 case HANDLER_GO_ON:
44513 @@ -72,18 +73,18 @@
44514         buffer *b;
44515         int is_unix_domain_socket = 0;
44516         int fd;
44517 -       
44518 +
44519  #ifdef SO_ACCEPTFILTER
44520         struct accept_filter_arg afa;
44521  #endif
44522  
44523 -#ifdef __WIN32
44524 +#ifdef _WIN32
44525         WORD wVersionRequested;
44526         WSADATA wsaData;
44527         int err;
44528 -        
44529 +
44530         wVersionRequested = MAKEWORD( 2, 2 );
44531 -        
44532 +
44533         err = WSAStartup( wVersionRequested, &wsaData );
44534         if ( err != 0 ) {
44535                     /* Tell the user that we could not find a usable */
44536 @@ -91,37 +92,37 @@
44537                     return -1;
44538         }
44539  #endif
44540 -       
44541 +
44542         srv_socket = calloc(1, sizeof(*srv_socket));
44543 -       srv_socket->fd = -1;
44544 -       
44545 +       srv_socket->sock = iosocket_init();
44546 +
44547         srv_socket->srv_token = buffer_init();
44548         buffer_copy_string_buffer(srv_socket->srv_token, host_token);
44549 -       
44550 +
44551         b = buffer_init();
44552         buffer_copy_string_buffer(b, host_token);
44553 -       
44554 -       /* ipv4:port 
44555 +
44556 +       /* ipv4:port
44557          * [ipv6]:port
44558          */
44559         if (NULL == (sp = strrchr(b->ptr, ':'))) {
44560                 log_error_write(srv, __FILE__, __LINE__, "sb", "value of $SERVER[\"socket\"] has to be \"ip:port\".", b);
44561 -               
44562 +
44563                 return -1;
44564         }
44565 -       
44566 +
44567         host = b->ptr;
44568 -       
44569 +
44570         /* check for [ and ] */
44571         if (b->ptr[0] == '[' && *(sp-1) == ']') {
44572                 *(sp-1) = '\0';
44573                 host++;
44574 -               
44575 +
44576                 s->use_ipv6 = 1;
44577         }
44578 -       
44579 +
44580         *(sp++) = '\0';
44581 -       
44582 +
44583         port = strtol(sp, NULL, 10);
44584  
44585         if (host[0] == '/') {
44586 @@ -129,18 +130,18 @@
44587                 is_unix_domain_socket = 1;
44588         } else if (port == 0 || port > 65535) {
44589                 log_error_write(srv, __FILE__, __LINE__, "sd", "port out of range:", port);
44590 -       
44591 +
44592                 return -1;
44593         }
44594 -       
44595 +
44596         if (*host == '\0') host = NULL;
44597  
44598         if (is_unix_domain_socket) {
44599  #ifdef HAVE_SYS_UN_H
44600  
44601                 srv_socket->addr.plain.sa_family = AF_UNIX;
44602 -               
44603 -               if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
44604 +
44605 +               if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
44606                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44607                         return -1;
44608                 }
44609 @@ -154,32 +155,32 @@
44610  #ifdef HAVE_IPV6
44611         if (s->use_ipv6) {
44612                 srv_socket->addr.plain.sa_family = AF_INET6;
44613 -               
44614 -               if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44615 +
44616 +               if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44617                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44618                         return -1;
44619                 }
44620                 srv_socket->use_ipv6 = 1;
44621         }
44622  #endif
44623 -                               
44624 -       if (srv_socket->fd == -1) {
44625 +
44626 +       if (srv_socket->sock->fd == -1) {
44627                 srv_socket->addr.plain.sa_family = AF_INET;
44628 -               if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44629 +               if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44630                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44631                         return -1;
44632                 }
44633         }
44634 -       
44635 +
44636         /* */
44637 -       srv->cur_fds = srv_socket->fd;
44638 -       
44639 +       srv->cur_fds = srv_socket->sock->fd;
44640 +
44641         val = 1;
44642 -       if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
44643 +       if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
44644                 log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt failed:", strerror(errno));
44645                 return -1;
44646         }
44647 -       
44648 +
44649         switch(srv_socket->addr.plain.sa_family) {
44650  #ifdef HAVE_IPV6
44651         case AF_INET6:
44652 @@ -190,23 +191,23 @@
44653                 } else {
44654                         struct addrinfo hints, *res;
44655                         int r;
44656 -                       
44657 +
44658                         memset(&hints, 0, sizeof(hints));
44659 -                       
44660 +
44661                         hints.ai_family   = AF_INET6;
44662                         hints.ai_socktype = SOCK_STREAM;
44663                         hints.ai_protocol = IPPROTO_TCP;
44664 -                       
44665 +
44666                         if (0 != (r = getaddrinfo(host, NULL, &hints, &res))) {
44667 -                               log_error_write(srv, __FILE__, __LINE__, 
44668 -                                               "sssss", "getaddrinfo failed: ", 
44669 +                               log_error_write(srv, __FILE__, __LINE__,
44670 +                                               "sssss", "getaddrinfo failed: ",
44671                                                 gai_strerror(r), "'", host, "'");
44672 -                               
44673 +
44674                                 return -1;
44675                         }
44676 -                       
44677 +
44678                         memcpy(&(srv_socket->addr), res->ai_addr, res->ai_addrlen);
44679 -                       
44680 +
44681                         freeaddrinfo(res);
44682                 }
44683                 srv_socket->addr.ipv6.sin6_port = htons(port);
44684 @@ -221,33 +222,34 @@
44685                 } else {
44686                         struct hostent *he;
44687                         if (NULL == (he = gethostbyname(host))) {
44688 -                               log_error_write(srv, __FILE__, __LINE__, 
44689 -                                               "sds", "gethostbyname failed: ", 
44690 +                               log_error_write(srv, __FILE__, __LINE__,
44691 +                                               "sds", "gethostbyname failed: ",
44692                                                 h_errno, host);
44693                                 return -1;
44694                         }
44695 -                       
44696 +
44697                         if (he->h_addrtype != AF_INET) {
44698                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
44699                                 return -1;
44700                         }
44701 -                       
44702 +
44703                         if (he->h_length != sizeof(struct in_addr)) {
44704                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
44705                                 return -1;
44706                         }
44707 -                       
44708 +
44709                         memcpy(&(srv_socket->addr.ipv4.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
44710                 }
44711                 srv_socket->addr.ipv4.sin_port = htons(port);
44712 -               
44713 +
44714                 addr_len = sizeof(struct sockaddr_in);
44715 -               
44716 +
44717                 break;
44718 +#ifndef _WIN32
44719         case AF_UNIX:
44720                 srv_socket->addr.un.sun_family = AF_UNIX;
44721                 strcpy(srv_socket->addr.un.sun_path, host);
44722 -               
44723 +
44724  #ifdef SUN_LEN
44725                 addr_len = SUN_LEN(&srv_socket->addr.un);
44726  #else
44727 @@ -256,11 +258,11 @@
44728  #endif
44729  
44730                 /* check if the socket exists and try to connect to it. */
44731 -               if (-1 != (fd = connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
44732 +               if (-1 != (fd = connect(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
44733                         close(fd);
44734  
44735 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
44736 -                               "server socket is still in use:", 
44737 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
44738 +                               "server socket is still in use:",
44739                                 host);
44740  
44741  
44742 @@ -275,88 +277,89 @@
44743                 case ENOENT:
44744                         break;
44745                 default:
44746 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
44747 -                               "testing socket failed:", 
44748 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
44749 +                               "testing socket failed:",
44750                                 host, strerror(errno));
44751  
44752                         return -1;
44753                 }
44754  
44755                 break;
44756 +#endif
44757         default:
44758                 addr_len = 0;
44759 -               
44760 +
44761                 return -1;
44762         }
44763 -       
44764 -       if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
44765 +
44766 +       if (0 != bind(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
44767                 switch(srv_socket->addr.plain.sa_family) {
44768                 case AF_UNIX:
44769 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
44770 -                                       "can't bind to socket:", 
44771 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
44772 +                                       "can't bind to socket:",
44773                                         host, strerror(errno));
44774                         break;
44775                 default:
44776 -                       log_error_write(srv, __FILE__, __LINE__, "ssds", 
44777 -                                       "can't bind to port:", 
44778 +                       log_error_write(srv, __FILE__, __LINE__, "ssds",
44779 +                                       "can't bind to port:",
44780                                         host, port, strerror(errno));
44781                         break;
44782                 }
44783                 return -1;
44784         }
44785 -       
44786 -       if (-1 == listen(srv_socket->fd, 128 * 8)) {
44787 +
44788 +       if (-1 == listen(srv_socket->sock->fd, 128 * 8)) {
44789                 log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));
44790                 return -1;
44791         }
44792 -       
44793 +
44794         if (s->is_ssl) {
44795  #ifdef USE_OPENSSL
44796                 if (srv->ssl_is_init == 0) {
44797                         SSL_load_error_strings();
44798                         SSL_library_init();
44799                         srv->ssl_is_init = 1;
44800 -                       
44801 +
44802                         if (0 == RAND_status()) {
44803 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
44804 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44805                                                 "not enough entropy in the pool");
44806                                 return -1;
44807                         }
44808                 }
44809 -               
44810 +
44811                 if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
44812 -                       log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
44813 +                       log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44814                                         ERR_error_string(ERR_get_error(), NULL));
44815                         return -1;
44816                 }
44817 -               
44818 +
44819                 if (buffer_is_empty(s->ssl_pemfile)) {
44820                         log_error_write(srv, __FILE__, __LINE__, "s", "ssl.pemfile has to be set");
44821                         return -1;
44822                 }
44823 -               
44824 +
44825                 if (!buffer_is_empty(s->ssl_ca_file)) {
44826                         if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {
44827 -                               log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", 
44828 +                               log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44829                                                 ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
44830                                 return -1;
44831                         }
44832                 }
44833 -               
44834 +
44835                 if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
44836 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", 
44837 +                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44838                                         ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
44839                         return -1;
44840                 }
44841 -               
44842 +
44843                 if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
44844 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", 
44845 +                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44846                                         ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
44847                         return -1;
44848                 }
44849 -               
44850 +
44851                 if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
44852 -                       log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:", 
44853 +                       log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
44854                                         "Private key does not match the certificate public key, reason:",
44855                                         ERR_error_string(ERR_get_error(), NULL),
44856                                         s->ssl_pemfile);
44857 @@ -364,15 +367,15 @@
44858                 }
44859                 srv_socket->ssl_ctx = s->ssl_ctx;
44860  #else
44861 -               
44862 +
44863                 buffer_free(srv_socket->srv_token);
44864                 free(srv_socket);
44865 -               
44866 +
44867                 buffer_free(b);
44868 -               
44869 -               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
44870 +
44871 +               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44872                                 "ssl requested but openssl support is not compiled in");
44873 -               
44874 +
44875                 return -1;
44876  #endif
44877         } else {
44878 @@ -383,17 +386,16 @@
44879                  */
44880                 memset(&afa, 0, sizeof(afa));
44881                 strcpy(afa.af_name, "httpready");
44882 -               if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
44883 +               if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
44884                         if (errno != ENOENT) {
44885                                 log_error_write(srv, __FILE__, __LINE__, "ss", "can't set accept-filter 'httpready': ", strerror(errno));
44886                         }
44887                 }
44888  #endif
44889         }
44890 -       
44891 +
44892         srv_socket->is_ssl = s->is_ssl;
44893 -       srv_socket->fde_ndx = -1;
44894 -       
44895 +
44896         if (srv->srv_sockets.size == 0) {
44897                 srv->srv_sockets.size = 4;
44898                 srv->srv_sockets.used = 0;
44899 @@ -402,11 +404,10 @@
44900                 srv->srv_sockets.size += 4;
44901                 srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket));
44902         }
44903 -       
44904 +
44905         srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
44906 -       
44907         buffer_free(b);
44908 -       
44909 +
44910         return 0;
44911  }
44912  
44913 @@ -414,45 +415,60 @@
44914         size_t i;
44915         for (i = 0; i < srv->srv_sockets.used; i++) {
44916                 server_socket *srv_socket = srv->srv_sockets.ptr[i];
44917 -               
44918 -               if (srv_socket->fd != -1) {
44919 +
44920 +               if (srv_socket->sock->fd != -1) {
44921                         /* check if server fd are already registered */
44922 -                       if (srv_socket->fde_ndx != -1) {
44923 -                               fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
44924 -                               fdevent_unregister(srv->ev, srv_socket->fd);
44925 +                       if (srv_socket->sock->fde_ndx != -1) {
44926 +                               fdevent_event_del(srv->ev, srv_socket->sock);
44927 +                               fdevent_unregister(srv->ev, srv_socket->sock);
44928                         }
44929 -               
44930 -                       close(srv_socket->fd);
44931 +
44932 +                       closesocket(srv_socket->sock->fd);
44933 +               }
44934 +
44935 +               if (srv_socket->is_ssl) {
44936 +#ifdef USE_OPENSSL
44937 +                       SSL_CTX_free(srv_socket->ssl_ctx);
44938 +#endif
44939                 }
44940 -               
44941 +
44942 +               iosocket_free(srv_socket->sock);
44943 +
44944                 buffer_free(srv_socket->srv_token);
44945 -               
44946 +
44947                 free(srv_socket);
44948         }
44949 -       
44950 +
44951 +#ifdef USE_OPENSSL
44952 +       ERR_free_strings();
44953 +#endif
44954         free(srv->srv_sockets.ptr);
44955 -       
44956 +
44957         return 0;
44958  }
44959  
44960  typedef enum {
44961         NETWORK_BACKEND_UNSET,
44962 +
44963         NETWORK_BACKEND_WRITE,
44964         NETWORK_BACKEND_WRITEV,
44965         NETWORK_BACKEND_LINUX_SENDFILE,
44966         NETWORK_BACKEND_FREEBSD_SENDFILE,
44967 -       NETWORK_BACKEND_SOLARIS_SENDFILEV
44968 +       NETWORK_BACKEND_SOLARIS_SENDFILEV,
44969 +
44970 +    NETWORK_BACKEND_WIN32_SEND,
44971 +    NETWORK_BACKEND_WIN32_TRANSMITFILE,
44972  } network_backend_t;
44973  
44974  int network_init(server *srv) {
44975         buffer *b;
44976         size_t i;
44977         network_backend_t backend;
44978 -       
44979 -       struct nb_map { 
44980 -               network_backend_t nb; 
44981 -               const char *name; 
44982 -       } network_backends[] = { 
44983 +
44984 +       struct nb_map {
44985 +               network_backend_t nb;
44986 +               const char *name;
44987 +       } network_backends[] = {
44988                 /* lowest id wins */
44989  #if defined USE_LINUX_SENDFILE
44990                 { NETWORK_BACKEND_LINUX_SENDFILE,       "linux-sendfile" },
44991 @@ -466,21 +482,30 @@
44992  #if defined USE_WRITEV
44993                 { NETWORK_BACKEND_WRITEV,               "writev" },
44994  #endif
44995 +#if defined USE_WRITE
44996                 { NETWORK_BACKEND_WRITE,                "write" },
44997 +#endif
44998 +#if defined USE_WIN32_TRANSMITFILE
44999 +               { NETWORK_BACKEND_WIN32_TRANSMITFILE,   "win32-transmitfile" },
45000 +#endif
45001 +#if defined USE_WIN32_SEND
45002 +               { NETWORK_BACKEND_WIN32_SEND,           "win32-send" },
45003 +#endif
45004 +
45005                 { NETWORK_BACKEND_UNSET,                NULL }
45006         };
45007 -       
45008 +
45009         b = buffer_init();
45010 -               
45011 +
45012         buffer_copy_string_buffer(b, srv->srvconf.bindhost);
45013         buffer_append_string(b, ":");
45014         buffer_append_long(b, srv->srvconf.port);
45015 -       
45016 +
45017         if (0 != network_server_init(srv, b, srv->config_storage[0])) {
45018                 return -1;
45019         }
45020         buffer_free(b);
45021 -               
45022 +
45023  #ifdef USE_OPENSSL
45024         srv->network_ssl_backend_write = network_write_chunkqueue_openssl;
45025  #endif
45026 @@ -500,54 +525,80 @@
45027                 if (NULL == network_backends[i].name) {
45028                         /* we don't know it */
45029  
45030 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
45031 -                                       "server.network-backend has a unknown value:", 
45032 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
45033 +                                       "server.network-backend has a unknown value:",
45034                                         srv->srvconf.network_backend);
45035  
45036                         return -1;
45037                 }
45038         }
45039  
45040 +#define SET_NETWORK_BACKEND(read, write) \
45041 +    srv->network_backend_write = network_write_chunkqueue_##write;\
45042 +    srv->network_backend_read = network_read_chunkqueue_##read
45043 +
45044 +#define SET_NETWORK_BACKEND_SSL(read, write) \
45045 +    srv->network_ssl_backend_write = network_write_chunkqueue_##write;\
45046 +    srv->network_ssl_backend_read = network_read_chunkqueue_##read
45047 +
45048         switch(backend) {
45049 +
45050 +#ifdef USE_WIN32_SEND
45051 +       case NETWORK_BACKEND_WIN32_SEND:
45052 +        SET_NETWORK_BACKEND(win32recv, win32send);
45053 +               break;
45054 +#ifdef USE_WIN32_TRANSMITFILE
45055 +       case NETWORK_BACKEND_WIN32_TRANSMITFILE:
45056 +        SET_NETWORK_BACKEND(win32recv, win32transmitfile);
45057 +               break;
45058 +#endif
45059 +#endif
45060 +
45061 +#ifdef USE_WRITE
45062         case NETWORK_BACKEND_WRITE:
45063 -               srv->network_backend_write = network_write_chunkqueue_write;
45064 +        SET_NETWORK_BACKEND(read, write);
45065                 break;
45066 +
45067  #ifdef USE_WRITEV
45068         case NETWORK_BACKEND_WRITEV:
45069 -               srv->network_backend_write = network_write_chunkqueue_writev;
45070 +        SET_NETWORK_BACKEND(read, writev);
45071                 break;
45072  #endif
45073  #ifdef USE_LINUX_SENDFILE
45074         case NETWORK_BACKEND_LINUX_SENDFILE:
45075 -               srv->network_backend_write = network_write_chunkqueue_linuxsendfile; 
45076 +        SET_NETWORK_BACKEND(read, linuxsendfile);
45077                 break;
45078  #endif
45079  #ifdef USE_FREEBSD_SENDFILE
45080         case NETWORK_BACKEND_FREEBSD_SENDFILE:
45081 -               srv->network_backend_write = network_write_chunkqueue_freebsdsendfile; 
45082 +        SET_NETWORK_BACKEND(read, freebsdsendfile);
45083                 break;
45084  #endif
45085  #ifdef USE_SOLARIS_SENDFILEV
45086         case NETWORK_BACKEND_SOLARIS_SENDFILEV:
45087 -               srv->network_backend_write = network_write_chunkqueue_solarissendfilev; 
45088 +        SET_NETWORK_BACKEND(read, solarissendfilev);
45089                 break;
45090  #endif
45091 +#endif
45092         default:
45093                 return -1;
45094         }
45095 +#ifdef USE_OPENSSL
45096 +        SET_NETWORK_BACKEND_SSL(openssl, openssl);
45097 +#endif
45098  
45099         /* check for $SERVER["socket"] */
45100         for (i = 1; i < srv->config_context->used; i++) {
45101                 data_config *dc = (data_config *)srv->config_context->data[i];
45102                 specific_config *s = srv->config_storage[i];
45103                 size_t j;
45104 -               
45105 +
45106                 /* not our stage */
45107                 if (COMP_SERVER_SOCKET != dc->comp) continue;
45108 -               
45109 +
45110                 if (dc->cond != CONFIG_COND_EQ) {
45111                         log_error_write(srv, __FILE__, __LINE__, "s", "only == is allowed for $SERVER[\"socket\"].");
45112 -                       
45113 +
45114                         return -1;
45115                 }
45116  
45117 @@ -558,36 +609,47 @@
45118                                 break;
45119                         }
45120                 }
45121 -               
45122 +
45123                 if (j == srv->srv_sockets.used) {
45124                         if (0 != network_server_init(srv, dc->string, s)) return -1;
45125                 }
45126         }
45127 -       
45128 +
45129         return 0;
45130  }
45131  
45132  int network_register_fdevents(server *srv) {
45133         size_t i;
45134 -       
45135         if (-1 == fdevent_reset(srv->ev)) {
45136                 return -1;
45137         }
45138 -       
45139         /* register fdevents after reset */
45140         for (i = 0; i < srv->srv_sockets.used; i++) {
45141                 server_socket *srv_socket = srv->srv_sockets.ptr[i];
45142 -               
45143 -               fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
45144 -               fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
45145 +               fdevent_register(srv->ev, srv_socket->sock, network_server_handle_fdevent, srv_socket);
45146 +               fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
45147         }
45148         return 0;
45149  }
45150  
45151 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
45152 -       int ret = -1;
45153 +network_status_t network_read_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
45154 +       server_socket *srv_socket = con->srv_socket;
45155 +
45156 +       if (srv_socket->is_ssl) {
45157 +#ifdef USE_OPENSSL
45158 +               return srv->network_ssl_backend_read(srv, con, con->sock, cq);
45159 +#else
45160 +               return NETWORK_STATUS_FATAL_ERROR;
45161 +#endif
45162 +       } else {
45163 +               return srv->network_backend_read(srv, con, con->sock, cq);
45164 +       }
45165 +}
45166 +
45167 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
45168 +       network_status_t ret = NETWORK_STATUS_UNSET;
45169         off_t written = 0;
45170 -#ifdef TCP_CORK        
45171 +#ifdef TCP_CORK
45172         int corked = 0;
45173  #endif
45174         server_socket *srv_socket = con->srv_socket;
45175 @@ -600,37 +662,42 @@
45176                 joblist_append(srv, con);
45177  
45178                 return 1;
45179 -       }  
45180 +       }
45181  
45182         written = cq->bytes_out;
45183  
45184 -#ifdef TCP_CORK        
45185 +#ifdef TCP_CORK
45186         /* Linux: put a cork into the socket as we want to combine the write() calls
45187          * but only if we really have multiple chunks
45188          */
45189         if (cq->first && cq->first->next) {
45190                 corked = 1;
45191 -               setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
45192 +               setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
45193         }
45194  #endif
45195 -       
45196 +
45197         if (srv_socket->is_ssl) {
45198  #ifdef USE_OPENSSL
45199 -               ret = srv->network_ssl_backend_write(srv, con, con->ssl, cq);
45200 +               ret = srv->network_ssl_backend_write(srv, con, con->sock, cq);
45201  #endif
45202         } else {
45203 -               ret = srv->network_backend_write(srv, con, con->fd, cq);
45204 +               ret = srv->network_backend_write(srv, con, con->sock, cq);
45205         }
45206 -       
45207 -       if (ret >= 0) {
45208 +
45209 +    switch (ret) {
45210 +    case NETWORK_STATUS_WAIT_FOR_EVENT:
45211 +    case NETWORK_STATUS_SUCCESS:
45212                 chunkqueue_remove_finished_chunks(cq);
45213 -               ret = chunkqueue_is_empty(cq) ? 0 : 1;
45214 +
45215 +        break;
45216 +    default:
45217 +        break;
45218         }
45219 -       
45220 +
45221  #ifdef TCP_CORK
45222         if (corked) {
45223                 corked = 0;
45224 -               setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
45225 +               setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
45226         }
45227  #endif
45228  
45229 @@ -639,13 +706,13 @@
45230         con->bytes_written_cur_second += written;
45231  
45232         *(con->conf.global_bytes_per_second_cnt_ptr) += written;
45233 -       
45234 +
45235         if (con->conf.kbytes_per_second &&
45236             (con->bytes_written_cur_second > con->conf.kbytes_per_second * 1024)) {
45237                 /* we reached the traffic limit */
45238  
45239                 con->traffic_limit_reached = 1;
45240                 joblist_append(srv, con);
45241 -       }  
45242 +       }
45243         return ret;
45244  }
45245 --- ../lighttpd-1.4.11/src/network.h    2005-08-11 01:26:42.000000000 +0300
45246 +++ lighttpd-1.4.12/src/network.h       2006-07-18 13:03:40.000000000 +0300
45247 @@ -3,11 +3,13 @@
45248  
45249  #include "server.h"
45250  
45251 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
45252 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
45253 +network_status_t network_read_chunkqueue(server *srv, connection *con, chunkqueue *c);
45254  
45255  int network_init(server *srv);
45256  int network_close(server *srv);
45257  
45258  int network_register_fdevents(server *srv);
45259 +handler_t network_server_handle_fdevent(void *s, void *context, int revents);
45260  
45261  #endif
45262 --- ../lighttpd-1.4.11/src/network_backends.h   2005-10-24 15:13:51.000000000 +0300
45263 +++ lighttpd-1.4.12/src/network_backends.h      2006-07-18 13:03:40.000000000 +0300
45264 @@ -43,16 +43,47 @@
45265  # define USE_AIX_SENDFILE
45266  #endif
45267  
45268 +/**
45269 +* unix can use read/write or recv/send on sockets
45270 +* win32 only recv/send
45271 +*/
45272 +#ifdef _WIN32
45273 +# define USE_WIN32_SEND
45274 +/* wait for async-io support
45275 +# define USE_WIN32_TRANSMITFILE
45276 +*/
45277 +#else
45278 +# define USE_WRITE
45279 +#endif
45280 +
45281  #include "base.h"
45282 +#include "network.h"
45283 +
45284 +#define NETWORK_BACKEND_WRITE_CHUNK(x) \
45285 +    network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq, chunk *c)
45286 +
45287 +#define NETWORK_BACKEND_WRITE(x) \
45288 +    network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
45289 +#define NETWORK_BACKEND_READ(x) \
45290 +    network_status_t network_read_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
45291 +
45292 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem);
45293 +
45294 +NETWORK_BACKEND_WRITE(write);
45295 +NETWORK_BACKEND_WRITE(writev);
45296 +NETWORK_BACKEND_WRITE(linuxsendfile);
45297 +NETWORK_BACKEND_WRITE(freebsdsendfile);
45298 +NETWORK_BACKEND_WRITE(solarissendfilev);
45299 +
45300 +NETWORK_BACKEND_WRITE(win32transmitfile);
45301 +NETWORK_BACKEND_WRITE(win32send);
45302  
45303 +NETWORK_BACKEND_READ(read);
45304 +NETWORK_BACKEND_READ(win32recv);
45305  
45306 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq);
45307 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq);
45308 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
45309 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
45310 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq);
45311  #ifdef USE_OPENSSL
45312 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq);
45313 +NETWORK_BACKEND_WRITE(openssl);
45314 +NETWORK_BACKEND_READ(openssl);
45315  #endif
45316  
45317  #endif
45318 --- ../lighttpd-1.4.11/src/network_freebsd_sendfile.c   2005-10-22 12:28:18.000000000 +0300
45319 +++ lighttpd-1.4.12/src/network_freebsd_sendfile.c      2006-07-16 00:26:04.000000000 +0300
45320 @@ -26,142 +26,61 @@
45321  
45322  #ifndef UIO_MAXIOV
45323  # ifdef __FreeBSD__
45324 -/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */ 
45325 +/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
45326  #  define UIO_MAXIOV 1024
45327  # endif
45328  #endif
45329  
45330 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
45331 +NETWORK_BACKEND_WRITE(freebsdsendfile) {
45332         chunk *c;
45333         size_t chunks_written = 0;
45334 -       
45335 +
45336         for(c = cq->first; c; c = c->next, chunks_written++) {
45337                 int chunk_finished = 0;
45338 -               
45339 +               network_status_t ret;
45340 +
45341                 switch(c->type) {
45342 -               case MEM_CHUNK: {
45343 -                       char * offset;
45344 -                       size_t toSend;
45345 -                       ssize_t r;
45346 -                       
45347 -                       size_t num_chunks, i;
45348 -                       struct iovec chunks[UIO_MAXIOV];
45349 -                       chunk *tc;
45350 -                       size_t num_bytes = 0;
45351 -                       
45352 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
45353 -                       
45354 -                       /* build writev list 
45355 -                        * 
45356 -                        * 1. limit: num_chunks < UIO_MAXIOV
45357 -                        * 2. limit: num_bytes < SSIZE_MAX
45358 -                        */
45359 -                       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
45360 -                       
45361 -                       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
45362 -                               if (tc->mem->used == 0) {
45363 -                                       chunks[i].iov_base = tc->mem->ptr;
45364 -                                       chunks[i].iov_len  = 0;
45365 -                               } else {
45366 -                                       offset = tc->mem->ptr + tc->offset;
45367 -                                       toSend = tc->mem->used - 1 - tc->offset;
45368 -                                       
45369 -                                       chunks[i].iov_base = offset;
45370 -                                       
45371 -                                       /* protect the return value of writev() */
45372 -                                       if (toSend > SSIZE_MAX ||
45373 -                                           num_bytes + toSend > SSIZE_MAX) {
45374 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
45375 -                                               
45376 -                                               num_chunks = i + 1;
45377 -                                               break;
45378 -                                       } else {
45379 -                                               chunks[i].iov_len = toSend;
45380 -                                       }
45381 -                                
45382 -                                       num_bytes += toSend;
45383 -                               }
45384 -                       }
45385 -                       
45386 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
45387 -                               switch (errno) {
45388 -                               case EAGAIN:
45389 -                               case EINTR:
45390 -                                       r = 0;
45391 -                                       break;
45392 -                               case EPIPE:
45393 -                               case ECONNRESET:
45394 -                                       return -2;
45395 -                               default:
45396 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
45397 -                                                       "writev failed:", strerror(errno), fd);
45398 -                                       
45399 -                                       return -1;
45400 -                               }
45401 +               case MEM_CHUNK:
45402 +                       ret = network_write_chunkqueue_writev_mem(srv, con, fd, cq, &c);
45403  
45404 -                               r = 0;
45405 -                       }
45406 -                       
45407 -                       /* check which chunks have been written */
45408 -                       cq->bytes_out += r;
45409 -                       
45410 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
45411 -                               if (r >= (ssize_t)chunks[i].iov_len) {
45412 -                                       /* written */
45413 -                                       r -= chunks[i].iov_len;
45414 -                                       tc->offset += chunks[i].iov_len;
45415 -                                       
45416 -                                       if (chunk_finished) {
45417 -                                               /* skip the chunks from further touches */
45418 -                                               chunks_written++;
45419 -                                               c = c->next;
45420 -                                       } else {
45421 -                                               /* chunks_written + c = c->next is done in the for()*/
45422 -                                               chunk_finished++;
45423 -                                       }
45424 -                               } else {
45425 -                                       /* partially written */
45426 -                                       
45427 -                                       tc->offset += r;
45428 -                                       chunk_finished = 0;
45429 -                                       
45430 -                                       break;
45431 -                               }
45432 +                       if (ret != NETWORK_STATUS_SUCCESS) {
45433 +                               return ret;
45434                         }
45435 -                       
45436 +
45437 +                       chunk_finished = 1;
45438 +
45439                         break;
45440 -               }
45441                 case FILE_CHUNK: {
45442                         off_t offset, r;
45443                         size_t toSend;
45444                         stat_cache_entry *sce = NULL;
45445                         int ifd;
45446 -                       
45447 +
45448                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45449                                 log_error_write(srv, __FILE__, __LINE__, "sb",
45450                                                 strerror(errno), c->file.name);
45451 -                               return -1;
45452 +                               return NETWORK_STATUS_FATAL_ERROR;
45453                         }
45454 -                       
45455 +
45456                         offset = c->file.start + c->offset;
45457                         /* limit the toSend to 2^31-1 bytes in a chunk */
45458 -                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ? 
45459 +                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
45460                                 ((1 << 30) - 1) : c->file.length - c->offset;
45461 -                               
45462 +
45463                         if (offset > sce->st.st_size) {
45464                                 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
45465 -                               
45466 -                               return -1;
45467 +
45468 +                               return NETWORK_STATUS_FATAL_ERROR;
45469                         }
45470 -                       
45471 +
45472                         if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
45473                                 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
45474 -                               
45475 -                               return -1;
45476 +
45477 +                               return NETWORK_STATUS_FATAL_ERROR;
45478                         }
45479 -                       
45480 +
45481                         r = 0;
45482 -                       
45483 +
45484                         /* FreeBSD sendfile() */
45485                         if (-1 == sendfile(ifd, fd, offset, toSend, NULL, &r, 0)) {
45486                                 switch(errno) {
45487 @@ -169,39 +88,39 @@
45488                                         break;
45489                                 case ENOTCONN:
45490                                         close(ifd);
45491 -                                       return -2;
45492 +                                       return NETWORK_STATUS_CONNECTION_CLOSE;
45493                                 default:
45494                                         log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
45495                                         close(ifd);
45496 -                                       return -1;
45497 +                                       return NETWORK_STATUS_FATAL_ERROR;
45498                                 }
45499                         }
45500                         close(ifd);
45501 -                       
45502 +
45503                         c->offset += r;
45504                         cq->bytes_out += r;
45505 -                       
45506 +
45507                         if (c->offset == c->file.length) {
45508                                 chunk_finished = 1;
45509                         }
45510 -                       
45511 +
45512                         break;
45513                 }
45514                 default:
45515 -                       
45516 +
45517                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
45518 -                       
45519 +
45520                         return -1;
45521                 }
45522 -               
45523 +
45524                 if (!chunk_finished) {
45525                         /* not finished yet */
45526 -                       
45527 +
45528                         break;
45529                 }
45530         }
45531  
45532 -       return chunks_written;
45533 +       return NETWORK_STATUS_SUCCESS;
45534  }
45535  
45536  #endif
45537 --- ../lighttpd-1.4.11/src/network_linux_sendfile.c     2006-02-15 20:02:36.000000000 +0200
45538 +++ lighttpd-1.4.12/src/network_linux_sendfile.c        2006-07-18 13:03:40.000000000 +0300
45539 @@ -26,122 +26,54 @@
45540  /* on linux 2.4.29 + debian/ubuntu we have crashes if this is enabled */
45541  #undef HAVE_POSIX_FADVISE
45542  
45543 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
45544 -       chunk *c;
45545 +NETWORK_BACKEND_WRITE(linuxsendfile) {
45546 +       chunk *c, *tc;
45547         size_t chunks_written = 0;
45548 -       
45549 +
45550         for(c = cq->first; c; c = c->next, chunks_written++) {
45551                 int chunk_finished = 0;
45552 -               
45553 +               network_status_t ret;
45554 +
45555                 switch(c->type) {
45556 -               case MEM_CHUNK: {
45557 -                       char * offset;
45558 -                       size_t toSend;
45559 -                       ssize_t r;
45560 -                       
45561 -                       size_t num_chunks, i;
45562 -                       struct iovec chunks[UIO_MAXIOV];
45563 -                       chunk *tc;
45564 -                       size_t num_bytes = 0;
45565 -                       
45566 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
45567 -                       
45568 -                       /* build writev list 
45569 -                        * 
45570 -                        * 1. limit: num_chunks < UIO_MAXIOV
45571 -                        * 2. limit: num_bytes < SSIZE_MAX
45572 -                        */
45573 -                       for (num_chunks = 0, tc = c; 
45574 -                            tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; 
45575 -                            tc = tc->next, num_chunks++);
45576 -                       
45577 -                       for (tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
45578 -                               if (tc->mem->used == 0) {
45579 -                                       chunks[i].iov_base = tc->mem->ptr;
45580 -                                       chunks[i].iov_len  = 0;
45581 -                               } else {
45582 -                                       offset = tc->mem->ptr + tc->offset;
45583 -                                       toSend = tc->mem->used - 1 - tc->offset;
45584 -                               
45585 -                                       chunks[i].iov_base = offset;
45586 -                                       
45587 -                                       /* protect the return value of writev() */
45588 -                                       if (toSend > SSIZE_MAX ||
45589 -                                           num_bytes + toSend > SSIZE_MAX) {
45590 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
45591 -                                               
45592 -                                               num_chunks = i + 1;
45593 -                                               break;
45594 -                                       } else {
45595 -                                               chunks[i].iov_len = toSend;
45596 -                                       }
45597 -                                
45598 -                                       num_bytes += toSend;
45599 -                               }
45600 -                       }
45601 -                       
45602 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
45603 -                               switch (errno) {
45604 -                               case EAGAIN:
45605 -                               case EINTR:
45606 -                                       r = 0;
45607 -                                       break;
45608 -                               case EPIPE:
45609 -                               case ECONNRESET:
45610 -                                       return -2;
45611 -                               default:
45612 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
45613 -                                                       "writev failed:", strerror(errno), fd);
45614 -                               
45615 -                                       return -1;
45616 -                               }
45617 -                       }
45618 -                       
45619 -                       /* check which chunks have been written */
45620 -                       cq->bytes_out += r;
45621 +               case MEM_CHUNK:
45622 +                       ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
45623  
45624 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
45625 -                               if (r >= (ssize_t)chunks[i].iov_len) {
45626 -                                       /* written */
45627 -                                       r -= chunks[i].iov_len;
45628 -                                       tc->offset += chunks[i].iov_len;
45629 -                                       
45630 +                       /* check which chunks are finished now */
45631 +                       for (tc = c; tc; tc = tc->next) {
45632 +                               /* finished the chunk */
45633 +                               if (tc->offset == tc->mem->used - 1) {
45634 +                                       /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
45635                                         if (chunk_finished) {
45636 -                                               /* skip the chunks from further touches */
45637 -                                               chunks_written++;
45638                                                 c = c->next;
45639                                         } else {
45640 -                                               /* chunks_written + c = c->next is done in the for()*/
45641 -                                               chunk_finished++;
45642 +                                               chunk_finished = 1;
45643                                         }
45644                                 } else {
45645 -                                       /* partially written */
45646 -                                       
45647 -                                       tc->offset += r;
45648 -                                       chunk_finished = 0;
45649 -                                       
45650                                         break;
45651                                 }
45652                         }
45653 -                       
45654 +
45655 +                       if (ret != NETWORK_STATUS_SUCCESS) {
45656 +                               return ret;
45657 +                       }
45658 +
45659                         break;
45660 -               }
45661                 case FILE_CHUNK: {
45662                         ssize_t r;
45663                         off_t offset;
45664                         size_t toSend;
45665                         stat_cache_entry *sce = NULL;
45666 -                       
45667 +
45668                         offset = c->file.start + c->offset;
45669                         /* limit the toSend to 2^31-1 bytes in a chunk */
45670 -                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ? 
45671 +                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
45672                                 ((1 << 30) - 1) : c->file.length - c->offset;
45673 -                               
45674 -                       /* open file if not already opened */   
45675 +
45676 +                       /* open file if not already opened */
45677                         if (-1 == c->file.fd) {
45678                                 if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
45679                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
45680 -                               
45681 +
45682                                         return -1;
45683                                 }
45684  #ifdef FD_CLOEXEC
45685 @@ -151,14 +83,14 @@
45686                                 /* tell the kernel that we want to stream the file */
45687                                 if (-1 == posix_fadvise(c->file.fd, 0, 0, POSIX_FADV_SEQUENTIAL)) {
45688                                         if (ENOSYS != errno) {
45689 -                                               log_error_write(srv, __FILE__, __LINE__, "ssd", 
45690 +                                               log_error_write(srv, __FILE__, __LINE__, "ssd",
45691                                                         "posix_fadvise failed:", strerror(errno), c->file.fd);
45692                                         }
45693                                 }
45694  #endif
45695                         }
45696  
45697 -                       if (-1 == (r = sendfile(fd, c->file.fd, &offset, toSend))) {
45698 +                       if (-1 == (r = sendfile(sock->fd, c->file.fd, &offset, toSend))) {
45699                                 switch (errno) {
45700                                 case EAGAIN:
45701                                 case EINTR:
45702 @@ -166,11 +98,11 @@
45703                                         break;
45704                                 case EPIPE:
45705                                 case ECONNRESET:
45706 -                                       return -2;
45707 +                                       return NETWORK_STATUS_CONNECTION_CLOSE;
45708                                 default:
45709 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
45710 -                                                       "sendfile failed:", strerror(errno), fd);
45711 -                                       return -1;
45712 +                                       log_error_write(srv, __FILE__, __LINE__, "ssd",
45713 +                                                       "sendfile failed:", strerror(errno), sock->fd);
45714 +                                       return NETWORK_STATUS_FATAL_ERROR;
45715                                 }
45716                         }
45717  
45718 @@ -179,39 +111,39 @@
45719                                  *
45720                                  * - the file shrinked -> error
45721                                  * - the remote side closed inbetween -> remote-close */
45722 -       
45723 +
45724                                 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45725                                         /* file is gone ? */
45726 -                                       return -1;
45727 +                                       return NETWORK_STATUS_FATAL_ERROR;
45728                                 }
45729  
45730                                 if (offset > sce->st.st_size) {
45731                                         /* file shrinked, close the connection */
45732 -                                       return -1;
45733 +                                       return NETWORK_STATUS_FATAL_ERROR;
45734                                 }
45735  
45736 -                               return -2;
45737 +                               return NETWORK_STATUS_CONNECTION_CLOSE;
45738                         }
45739  
45740  #ifdef HAVE_POSIX_FADVISE
45741  #if 0
45742  #define K * 1024
45743 -#define M * 1024 K     
45744 +#define M * 1024 K
45745  #define READ_AHEAD 4 M
45746                         /* check if we need a new chunk */
45747                         if ((c->offset & ~(READ_AHEAD - 1)) != ((c->offset + r) & ~(READ_AHEAD - 1))) {
45748                                 /* tell the kernel that we want to stream the file */
45749                                 if (-1 == posix_fadvise(c->file.fd, (c->offset + r) & ~(READ_AHEAD - 1), READ_AHEAD, POSIX_FADV_NOREUSE)) {
45750 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
45751 +                                       log_error_write(srv, __FILE__, __LINE__, "ssd",
45752                                                 "posix_fadvise failed:", strerror(errno), c->file.fd);
45753                                 }
45754                         }
45755  #endif
45756  #endif
45757 -                       
45758 +
45759                         c->offset += r;
45760                         cq->bytes_out += r;
45761 -                       
45762 +
45763                         if (c->offset == c->file.length) {
45764                                 chunk_finished = 1;
45765  
45766 @@ -222,24 +154,24 @@
45767                                         c->file.fd = -1;
45768                                 }
45769                         }
45770 -                       
45771 +
45772                         break;
45773                 }
45774                 default:
45775 -                       
45776 +
45777                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
45778 -                       
45779 -                       return -1;
45780 +
45781 +                       return NETWORK_STATUS_FATAL_ERROR;
45782                 }
45783 -               
45784 +
45785                 if (!chunk_finished) {
45786                         /* not finished yet */
45787 -                       
45788 -                       break;
45789 +
45790 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
45791                 }
45792         }
45793  
45794 -       return chunks_written;
45795 +       return NETWORK_STATUS_SUCCESS;
45796  }
45797  
45798  #endif
45799 --- ../lighttpd-1.4.11/src/network_openssl.c    2005-11-17 14:53:29.000000000 +0200
45800 +++ lighttpd-1.4.12/src/network_openssl.c       2006-07-18 13:03:40.000000000 +0300
45801 @@ -23,17 +23,87 @@
45802  #include "log.h"
45803  #include "stat_cache.h"
45804  
45805 -# include <openssl/ssl.h> 
45806 -# include <openssl/err.h> 
45807 +# include <openssl/ssl.h>
45808 +# include <openssl/err.h>
45809  
45810 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq) {
45811 +NETWORK_BACKEND_READ(openssl) {
45812 +       buffer *b;
45813 +       off_t len;
45814 +
45815 +       b = chunkqueue_get_append_buffer(cq);
45816 +       buffer_prepare_copy(b, 8192);
45817 +       len = SSL_read(sock->ssl, b->ptr, b->size - 1);
45818 +
45819 +       log_error_write(srv, __FILE__, __LINE__, "so", "SSL:", len);
45820 +
45821 +       if (len < 0) {
45822 +               int r, ssl_err;
45823 +
45824 +               switch ((r = SSL_get_error(sock->ssl, len))) {
45825 +               case SSL_ERROR_WANT_READ:
45826 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
45827 +               case SSL_ERROR_SYSCALL:
45828 +                       /**
45829 +                        * man SSL_get_error()
45830 +                        *
45831 +                        * SSL_ERROR_SYSCALL
45832 +                        *   Some I/O error occurred.  The OpenSSL error queue may contain more
45833 +                        *   information on the error.  If the error queue is empty (i.e.
45834 +                        *   ERR_get_error() returns 0), ret can be used to find out more about
45835 +                        *   the error: If ret == 0, an EOF was observed that violates the
45836 +                        *   protocol.  If ret == -1, the underlying BIO reported an I/O error
45837 +                        *   (for socket I/O on Unix systems, consult errno for details).
45838 +                        *
45839 +                        */
45840 +                       while((ssl_err = ERR_get_error())) {
45841 +                               /* get all errors from the error-queue */
45842 +                               log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
45843 +                                               r, ERR_error_string(ssl_err, NULL));
45844 +                       }
45845 +
45846 +                       switch(errno) {
45847 +                       default:
45848 +                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45849 +                                               len, r, errno,
45850 +                                               strerror(errno));
45851 +                               break;
45852 +                       }
45853 +
45854 +                       break;
45855 +               case SSL_ERROR_ZERO_RETURN:
45856 +                       /* clean shutdown on the remote side */
45857 +
45858 +                       if (r == 0) {
45859 +                               /* FIXME: later */
45860 +                       }
45861 +
45862 +                       /* fall thourgh */
45863 +               default:
45864 +                       while((ssl_err = ERR_get_error())) {
45865 +                               /* get all errors from the error-queue */
45866 +                               log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
45867 +                                               r, ERR_error_string(ssl_err, NULL));
45868 +                       }
45869 +                       break;
45870 +               }
45871 +       }
45872 +
45873 +       assert(len > 0);
45874 +       b->used += len;
45875 +       b->ptr[b->used - 1] = '\0';
45876 +
45877 +       return NETWORK_STATUS_SUCCESS;
45878 +}
45879 +
45880 +
45881 +NETWORK_BACKEND_WRITE(openssl) {
45882         int ssl_r;
45883         chunk *c;
45884         size_t chunks_written = 0;
45885  
45886         /* this is a 64k sendbuffer
45887          *
45888 -        * it has to stay at the same location all the time to satisfy the needs 
45889 +        * it has to stay at the same location all the time to satisfy the needs
45890          * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
45891          *
45892          * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
45893 @@ -43,59 +113,61 @@
45894          * In reality we would like to use mmap() but we don't have a guarantee that
45895          * we get the same mmap() address for each call. On openbsd the mmap() address
45896          * even randomized.
45897 -        *   That means either we keep the mmap() open or we do a read() into a 
45898 -        * constant buffer 
45899 +        *   That means either we keep the mmap() open or we do a read() into a
45900 +        * constant buffer
45901          * */
45902  #define LOCAL_SEND_BUFSIZE (64 * 1024)
45903         static char *local_send_buffer = NULL;
45904  
45905         /* the remote side closed the connection before without shutdown request
45906 -        * - IE 
45907 +        * - IE
45908          * - wget
45909          * if keep-alive is disabled */
45910  
45911         if (con->keep_alive == 0) {
45912 -               SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
45913 +               SSL_set_shutdown(sock->ssl, SSL_RECEIVED_SHUTDOWN);
45914         }
45915  
45916         for(c = cq->first; c; c = c->next) {
45917                 int chunk_finished = 0;
45918 -               
45919 +
45920                 switch(c->type) {
45921                 case MEM_CHUNK: {
45922                         char * offset;
45923                         size_t toSend;
45924 -                       ssize_t r;
45925 -                       
45926 +                       ssize_t r = 0;
45927 +
45928                         if (c->mem->used == 0) {
45929                                 chunk_finished = 1;
45930                                 break;
45931                         }
45932 -                       
45933 +
45934                         offset = c->mem->ptr + c->offset;
45935                         toSend = c->mem->used - 1 - c->offset;
45936 -                       
45937 +
45938                         /**
45939                          * SSL_write man-page
45940 -                        * 
45941 +                        *
45942                          * WARNING
45943                          *        When an SSL_write() operation has to be repeated because of
45944                          *        SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
45945                          *        repeated with the same arguments.
45946 -                        * 
45947 +                        *
45948 +                        * SSL_write(..., 0) return 0 which is handle as an error (Success)
45949 +                        * checking toSend and not calling SSL_write() is simpler
45950                          */
45951 -                       
45952 -                       if ((r = SSL_write(ssl, offset, toSend)) <= 0) {
45953 +
45954 +                       if (toSend != 0 && (r = SSL_write(sock->ssl, offset, toSend)) <= 0) {
45955                                 unsigned long err;
45956  
45957 -                               switch ((ssl_r = SSL_get_error(ssl, r))) {
45958 +                               switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
45959                                 case SSL_ERROR_WANT_WRITE:
45960                                         break;
45961                                 case SSL_ERROR_SYSCALL:
45962                                         /* perhaps we have error waiting in our error-queue */
45963                                         if (0 != (err = ERR_get_error())) {
45964                                                 do {
45965 -                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
45966 +                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45967                                                                         ssl_r, r,
45968                                                                         ERR_error_string(err, NULL));
45969                                                 } while((err = ERR_get_error()));
45970 @@ -105,43 +177,43 @@
45971                                                 case EPIPE:
45972                                                         return -2;
45973                                                 default:
45974 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", 
45975 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45976                                                                         ssl_r, r, errno,
45977                                                                         strerror(errno));
45978                                                         break;
45979                                                 }
45980                                         } else {
45981                                                 /* neither error-queue nor errno ? */
45982 -                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", 
45983 +                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
45984                                                                 ssl_r, r, errno,
45985                                                                 strerror(errno));
45986                                         }
45987 -                                       
45988 +
45989                                         return  -1;
45990                                 case SSL_ERROR_ZERO_RETURN:
45991                                         /* clean shutdown on the remote side */
45992 -                                       
45993 +
45994                                         if (r == 0) return -2;
45995 -                                       
45996 +
45997                                         /* fall through */
45998                                 default:
45999                                         while((err = ERR_get_error())) {
46000 -                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
46001 +                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
46002                                                                 ssl_r, r,
46003                                                                 ERR_error_string(err, NULL));
46004                                         }
46005 -                                       
46006 +
46007                                         return  -1;
46008                                 }
46009                         } else {
46010                                 c->offset += r;
46011                                 cq->bytes_out += r;
46012                         }
46013 -                       
46014 +
46015                         if (c->offset == (off_t)c->mem->used - 1) {
46016                                 chunk_finished = 1;
46017                         }
46018 -                       
46019 +
46020                         break;
46021                 }
46022                 case FILE_CHUNK: {
46023 @@ -150,7 +222,7 @@
46024                         stat_cache_entry *sce = NULL;
46025                         int ifd;
46026                         int write_wait = 0;
46027 -                       
46028 +
46029                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46030                                 log_error_write(srv, __FILE__, __LINE__, "sb",
46031                                                 strerror(errno), c->file.name);
46032 @@ -164,13 +236,13 @@
46033  
46034                         do {
46035                                 off_t offset = c->file.start + c->offset;
46036 -                               off_t toSend = c->file.length - c->offset; 
46037 +                               off_t toSend = c->file.length - c->offset;
46038  
46039                                 if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
46040 -                       
46041 +
46042                                 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
46043                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed:", strerror(errno));
46044 -                               
46045 +
46046                                         return -1;
46047                                 }
46048  
46049 @@ -183,13 +255,13 @@
46050                                 }
46051  
46052                                 s = local_send_buffer;
46053 -                       
46054 +
46055                                 close(ifd);
46056 -                       
46057 -                               if ((r = SSL_write(ssl, s, toSend)) <= 0) {
46058 +
46059 +                               if ((r = SSL_write(sock->ssl, s, toSend)) <= 0) {
46060                                         unsigned long err;
46061  
46062 -                                       switch ((ssl_r = SSL_get_error(ssl, r))) {
46063 +                                       switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
46064                                         case SSL_ERROR_WANT_WRITE:
46065                                                 write_wait = 1;
46066                                                 break;
46067 @@ -197,7 +269,7 @@
46068                                                 /* perhaps we have error waiting in our error-queue */
46069                                                 if (0 != (err = ERR_get_error())) {
46070                                                         do {
46071 -                                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
46072 +                                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
46073                                                                                 ssl_r, r,
46074                                                                                 ERR_error_string(err, NULL));
46075                                                         } while((err = ERR_get_error()));
46076 @@ -207,62 +279,62 @@
46077                                                         case EPIPE:
46078                                                                 return -2;
46079                                                         default:
46080 -                                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", 
46081 +                                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
46082                                                                                 ssl_r, r, errno,
46083                                                                                 strerror(errno));
46084                                                                 break;
46085                                                         }
46086                                                 } else {
46087                                                         /* neither error-queue nor errno ? */
46088 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", 
46089 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
46090                                                                         ssl_r, r, errno,
46091                                                                         strerror(errno));
46092                                                 }
46093 -                                       
46094 +
46095                                                 return  -1;
46096                                         case SSL_ERROR_ZERO_RETURN:
46097                                                 /* clean shutdown on the remote side */
46098 -                                       
46099 +
46100                                                 if (r == 0)  return -2;
46101 -                                       
46102 +
46103                                                 /* fall thourgh */
46104                                         default:
46105                                                 while((err = ERR_get_error())) {
46106 -                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
46107 +                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
46108                                                                         ssl_r, r,
46109                                                                         ERR_error_string(err, NULL));
46110                                                 }
46111 -                                       
46112 +
46113                                                 return -1;
46114                                         }
46115                                 } else {
46116                                         c->offset += r;
46117                                         cq->bytes_out += r;
46118                                 }
46119 -                       
46120 +
46121                                 if (c->offset == c->file.length) {
46122                                         chunk_finished = 1;
46123                                 }
46124                         } while(!chunk_finished && !write_wait);
46125 -                       
46126 +
46127                         break;
46128                 }
46129                 default:
46130                         log_error_write(srv, __FILE__, __LINE__, "s", "type not known");
46131 -                       
46132 +
46133                         return -1;
46134                 }
46135 -                       
46136 +
46137                 if (!chunk_finished) {
46138                         /* not finished yet */
46139 -                       
46140 +
46141                         break;
46142                 }
46143 -                       
46144 +
46145                 chunks_written++;
46146         }
46147  
46148 -       return chunks_written;
46149 +       return NETWORK_STATUS_SUCCESS;
46150  }
46151  #endif
46152  
46153 --- ../lighttpd-1.4.11/src/network_solaris_sendfilev.c  2005-10-22 12:28:27.000000000 +0300
46154 +++ lighttpd-1.4.12/src/network_solaris_sendfilev.c     2006-07-16 00:26:04.000000000 +0300
46155 @@ -29,114 +29,34 @@
46156  #endif
46157  
46158  /**
46159 - * a very simple sendfilev() interface for solaris which can be optimised a lot more 
46160 + * a very simple sendfilev() interface for solaris which can be optimised a lot more
46161   * as solaris sendfilev() supports 'sending everythin in one syscall()'
46162 - * 
46163 - * If you want such an interface and need the performance, just give me an account on 
46164 - * a solaris box. 
46165 + *
46166 + * If you want such an interface and need the performance, just give me an account on
46167 + * a solaris box.
46168   *   - jan@kneschke.de
46169   */
46170  
46171  
46172 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq) {
46173 +NETWORK_BACKEND_WRITE(solarissendfilev) {
46174         chunk *c;
46175         size_t chunks_written = 0;
46176 -       
46177 +
46178         for(c = cq->first; c; c = c->next, chunks_written++) {
46179                 int chunk_finished = 0;
46180 -               
46181 +               network_status_t ret;
46182 +
46183                 switch(c->type) {
46184 -               case MEM_CHUNK: {
46185 -                       char * offset;
46186 -                       size_t toSend;
46187 -                       ssize_t r;
46188 -                       
46189 -                       size_t num_chunks, i;
46190 -                       struct iovec chunks[UIO_MAXIOV];
46191 -                       chunk *tc;
46192 -                       
46193 -                       size_t num_bytes = 0;
46194 -                       
46195 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
46196 -                       
46197 -                       /* build writev list 
46198 -                        * 
46199 -                        * 1. limit: num_chunks < UIO_MAXIOV
46200 -                        * 2. limit: num_bytes < SSIZE_MAX
46201 -                        */
46202 -                       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
46203 -                       
46204 -                       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
46205 -                               if (tc->mem->used == 0) {
46206 -                                       chunks[i].iov_base = tc->mem->ptr;
46207 -                                       chunks[i].iov_len  = 0;
46208 -                               } else {
46209 -                                       offset = tc->mem->ptr + tc->offset;
46210 -                                       toSend = tc->mem->used - 1 - tc->offset;
46211 -                               
46212 -                                       chunks[i].iov_base = offset;
46213 -                                       
46214 -                                       /* protect the return value of writev() */
46215 -                                       if (toSend > SSIZE_MAX ||
46216 -                                           num_bytes + toSend > SSIZE_MAX) {
46217 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
46218 -                                               
46219 -                                               num_chunks = i + 1;
46220 -                                               break;
46221 -                                       } else {
46222 -                                               chunks[i].iov_len = toSend;
46223 -                                       }
46224 -                                       
46225 -                                       num_bytes += toSend;
46226 -                               }
46227 -                       }
46228 -                       
46229 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
46230 -                               switch (errno) {
46231 -                               case EAGAIN:
46232 -                               case EINTR:
46233 -                                       r = 0;
46234 -                                       break;
46235 -                               case EPIPE:
46236 -                               case ECONNRESET:
46237 -                                       return -2;
46238 -                               default:
46239 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
46240 -                                                       "writev failed:", strerror(errno), fd);
46241 -                               
46242 -                                       return -1;
46243 -                               }
46244 -                       }
46245 -                       
46246 -                       /* check which chunks have been written */
46247 -                       cq->bytes_out += r;
46248 -                       
46249 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46250 -                               if (r >= (ssize_t)chunks[i].iov_len) {
46251 -                                       /* written */
46252 -                                       r -= chunks[i].iov_len;
46253 -                                       tc->offset += chunks[i].iov_len;
46254 -                                       
46255 -                                       if (chunk_finished) {
46256 -                                               /* skip the chunks from further touches */
46257 -                                               chunks_written++;
46258 -                                               c = c->next;
46259 -                                       } else {
46260 -                                               /* chunks_written + c = c->next is done in the for()*/
46261 -                                               chunk_finished++;
46262 -                                       }
46263 -                               } else {
46264 -                                       /* partially written */
46265 -                                       
46266 -                                       tc->offset += r;
46267 -                                       chunk_finished = 0;
46268 -                                       
46269 -                                       break;
46270 -                               }
46271 +               case MEM_CHUNK:
46272 +                       ret = network_write_chunkqueue_writev_mem(srv, con, fd, cq, &c);
46273 +
46274 +                       if (ret != NETWORK_STATUS_SUCCESS) {
46275 +                               return ret;
46276                         }
46277 -                       
46278 +
46279 +                       chunk_finished = 1;
46280 +
46281                         break;
46282 -               }
46283                 case FILE_CHUNK: {
46284                         ssize_t r;
46285                         off_t offset;
46286 @@ -144,25 +64,25 @@
46287                         sendfilevec_t fvec;
46288                         stat_cache_entry *sce = NULL;
46289                         int ifd;
46290 -                       
46291 +
46292                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46293                                 log_error_write(srv, __FILE__, __LINE__, "sb",
46294                                                 strerror(errno), c->file.name);
46295                                 return -1;
46296                         }
46297 -                                       
46298 +
46299                         offset = c->file.start + c->offset;
46300                         toSend = c->file.length - c->offset;
46301 -                       
46302 +
46303                         if (offset > sce->st.st_size) {
46304                                 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
46305 -                               
46306 +
46307                                 return -1;
46308                         }
46309  
46310                         if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
46311                                 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
46312 -                               
46313 +
46314                                 return -1;
46315                         }
46316  
46317 @@ -170,44 +90,43 @@
46318                         fvec.sfv_flag = 0;
46319                         fvec.sfv_off = offset;
46320                         fvec.sfv_len = toSend;
46321 -                       
46322 +
46323                         /* Solaris sendfilev() */
46324                         if (-1 == (r = sendfilev(fd, &fvec, 1, &written))) {
46325                                 if (errno != EAGAIN) {
46326                                         log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
46327 -                                       
46328 +
46329                                         close(ifd);
46330 -                                       return -1;
46331 +                                       return NETWORK_STATUS_FATAL_ERROR;
46332                                 }
46333 -                               
46334 +
46335                                 r = 0;
46336                         }
46337 -                       
46338 +
46339                         close(ifd);
46340                         c->offset += written;
46341                         cq->bytes_out += written;
46342 -                       
46343 +
46344                         if (c->offset == c->file.length) {
46345                                 chunk_finished = 1;
46346                         }
46347 -                       
46348 +
46349                         break;
46350                 }
46351                 default:
46352 -                       
46353                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
46354 -                       
46355 -                       return -1;
46356 +
46357 +                       return NETWORK_STATUS_FATAL_ERROR;
46358                 }
46359 -               
46360 +
46361                 if (!chunk_finished) {
46362                         /* not finished yet */
46363 -                       
46364 +
46365                         break;
46366                 }
46367         }
46368  
46369 -       return chunks_written;
46370 +       return NETWORK_STATUS_SUCCESS;
46371  }
46372  
46373  #endif
46374 --- ../lighttpd-1.4.11/src/network_write.c      2005-10-22 12:27:56.000000000 +0300
46375 +++ lighttpd-1.4.12/src/network_write.c 2006-07-18 13:03:40.000000000 +0300
46376 @@ -1,11 +1,11 @@
46377  #include <sys/types.h>
46378  #include <sys/stat.h>
46379 -#include <sys/time.h>
46380 +
46381  #include <errno.h>
46382  #include <fcntl.h>
46383 -#include <unistd.h>
46384  #include <string.h>
46385  #include <stdlib.h>
46386 +#include <assert.h>
46387  
46388  #include "network.h"
46389  #include "fdevent.h"
46390 @@ -13,9 +13,12 @@
46391  #include "stat_cache.h"
46392  
46393  #include "sys-socket.h"
46394 +#include "sys-files.h"
46395  
46396  #include "network_backends.h"
46397  
46398 +#ifdef USE_WRITE
46399 +
46400  #ifdef HAVE_SYS_FILIO_H
46401  # include <sys/filio.h>
46402  #endif
46403 @@ -24,47 +27,92 @@
46404  #include <sys/resource.h>
46405  #endif
46406  
46407 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq) {
46408 +
46409 +/**
46410 +* fill the chunkqueue will all the data that we can get
46411 +*
46412 +* this might be optimized into a readv() which uses the chunks
46413 +* as vectors
46414 +*/
46415 +NETWORK_BACKEND_READ(read) {
46416 +       int toread;
46417 +       buffer *b;
46418 +       off_t r;
46419 +
46420 +       /**
46421 +        * a EAGAIN is a successful read if we already read something to the chunkqueue
46422 +        */
46423 +       int read_something = 0;
46424 +
46425 +       /* use a chunk-size of 8k */
46426 +       do {
46427 +               toread = 8192;
46428 +
46429 +               b = chunkqueue_get_append_buffer(cq);
46430 +
46431 +               buffer_prepare_copy(b, toread);
46432 +
46433 +               if (-1 == (r = read(sock->fd, b->ptr, toread))) {
46434 +                       switch (errno) {
46435 +                       case EAGAIN:
46436 +                               /* remove the last chunk from the chunkqueue */
46437 +                               chunkqueue_remove_empty_last_chunk(cq);
46438 +                               return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
46439 +                       default:
46440 +                               ERROR("oops, read from fd=%d failed: %s (%d)", sock->fd, strerror(errno), errno );
46441 +
46442 +                               return NETWORK_STATUS_FATAL_ERROR;
46443 +                       }
46444 +               }
46445 +
46446 +               if (r == 0) {
46447 +                       chunkqueue_remove_empty_last_chunk(cq);
46448 +                       return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_CONNECTION_CLOSE;
46449 +               }
46450 +
46451 +               read_something = 1;
46452 +
46453 +               b->used = r;
46454 +               b->ptr[b->used++] = '\0';
46455 +       } while (r == toread); 
46456 +
46457 +       return NETWORK_STATUS_SUCCESS;
46458 +}
46459 +
46460 +NETWORK_BACKEND_WRITE(write) {
46461         chunk *c;
46462         size_t chunks_written = 0;
46463 -       
46464 +
46465         for(c = cq->first; c; c = c->next) {
46466                 int chunk_finished = 0;
46467 -               
46468 +
46469                 switch(c->type) {
46470                 case MEM_CHUNK: {
46471                         char * offset;
46472                         size_t toSend;
46473                         ssize_t r;
46474 -                       
46475 +
46476                         if (c->mem->used == 0) {
46477                                 chunk_finished = 1;
46478                                 break;
46479                         }
46480 -                       
46481 +
46482                         offset = c->mem->ptr + c->offset;
46483                         toSend = c->mem->used - 1 - c->offset;
46484 -#ifdef __WIN32 
46485 -                       if ((r = send(fd, offset, toSend, 0)) < 0) {
46486 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
46487 -                               
46488 -                               return -1;
46489 -                       }
46490 -#else
46491 -                       if ((r = write(fd, offset, toSend)) < 0) {
46492 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
46493 -                               
46494 -                               return -1;
46495 +
46496 +                       if ((r = write(sock->fd, offset, toSend)) < 0) {
46497 +                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), sock->fd);
46498 +
46499 +                               return NETWORK_STATUS_FATAL_ERROR;
46500                         }
46501 -#endif
46502 -                       
46503 +
46504                         c->offset += r;
46505                         cq->bytes_out += r;
46506 -                       
46507 +
46508                         if (c->offset == (off_t)c->mem->used - 1) {
46509                                 chunk_finished = 1;
46510                         }
46511 -                       
46512 +
46513                         break;
46514                 }
46515                 case FILE_CHUNK: {
46516 @@ -76,93 +124,89 @@
46517                         size_t toSend;
46518                         stat_cache_entry *sce = NULL;
46519                         int ifd;
46520 -                       
46521 +
46522                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46523                                 log_error_write(srv, __FILE__, __LINE__, "sb",
46524                                                 strerror(errno), c->file.name);
46525 -                               return -1;
46526 +                               return NETWORK_STATUS_FATAL_ERROR;
46527                         }
46528 -                       
46529 +
46530                         offset = c->file.start + c->offset;
46531                         toSend = c->file.length - c->offset;
46532 -                       
46533 +
46534                         if (offset > sce->st.st_size) {
46535                                 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
46536 -                               
46537 -                               return -1;
46538 +
46539 +                               return NETWORK_STATUS_FATAL_ERROR;
46540                         }
46541  
46542                         if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
46543                                 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
46544 -                               
46545 -                               return -1;
46546 +
46547 +                               return NETWORK_STATUS_FATAL_ERROR;
46548                         }
46549 -                       
46550 +
46551  #if defined USE_MMAP
46552                         if (MAP_FAILED == (p = mmap(0, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
46553                                 log_error_write(srv, __FILE__, __LINE__, "ss", "mmap failed: ", strerror(errno));
46554  
46555                                 close(ifd);
46556 -                               
46557 -                               return -1;
46558 +
46559 +                               return NETWORK_STATUS_FATAL_ERROR;
46560                         }
46561                         close(ifd);
46562  
46563 -                       if ((r = write(fd, p + offset, toSend)) <= 0) {
46564 +                       if ((r = write(sock->fd, p + offset, toSend)) <= 0) {
46565                                 log_error_write(srv, __FILE__, __LINE__, "ss", "write failed: ", strerror(errno));
46566                                 munmap(p, sce->st.st_size);
46567 -                               return -1;
46568 +                               return NETWORK_STATUS_FATAL_ERROR;
46569                         }
46570 -                       
46571 +
46572                         munmap(p, sce->st.st_size);
46573  #else
46574                         buffer_prepare_copy(srv->tmp_buf, toSend);
46575 -                       
46576 +
46577                         lseek(ifd, offset, SEEK_SET);
46578                         if (-1 == (toSend = read(ifd, srv->tmp_buf->ptr, toSend))) {
46579                                 log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
46580                                 close(ifd);
46581 -                               
46582 -                               return -1;
46583 +
46584 +                               return NETWORK_STATUS_FATAL_ERROR;
46585                         }
46586                         close(ifd);
46587  
46588 -                       if (-1 == (r = send(fd, srv->tmp_buf->ptr, toSend, 0))) {
46589 +                       if (-1 == (r = send(sock->fd, srv->tmp_buf->ptr, toSend, 0))) {
46590                                 log_error_write(srv, __FILE__, __LINE__, "ss", "write: ", strerror(errno));
46591 -                               
46592 -                               return -1;
46593 +
46594 +                               return NETWORK_STATUS_FATAL_ERROR;
46595                         }
46596  #endif
46597                         c->offset += r;
46598                         cq->bytes_out += r;
46599 -                       
46600 +
46601                         if (c->offset == c->file.length) {
46602                                 chunk_finished = 1;
46603                         }
46604 -                       
46605 +
46606                         break;
46607                 }
46608                 default:
46609 -                       
46610 +
46611                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
46612 -                       
46613 -                       return -1;
46614 +
46615 +                       return NETWORK_STATUS_FATAL_ERROR;
46616                 }
46617 -               
46618 +
46619                 if (!chunk_finished) {
46620                         /* not finished yet */
46621 -                       
46622 +
46623                         break;
46624                 }
46625 -               
46626 +
46627                 chunks_written++;
46628         }
46629  
46630 -       return chunks_written;
46631 +       return NETWORK_STATUS_SUCCESS;
46632  }
46633  
46634 -#if 0
46635 -network_write_init(void) {
46636 -       p->write = network_write_write_chunkset;
46637 -}
46638  #endif
46639 --- ../lighttpd-1.4.11/src/network_writev.c     2006-02-15 01:02:36.000000000 +0200
46640 +++ lighttpd-1.4.12/src/network_writev.c        2006-07-18 13:03:40.000000000 +0300
46641 @@ -28,10 +28,10 @@
46642  
46643  #ifndef UIO_MAXIOV
46644  # if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__)
46645 -/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */ 
46646 +/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */
46647  #  define UIO_MAXIOV 1024
46648  # elif defined(__sgi)
46649 -/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */ 
46650 +/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */
46651  #  define UIO_MAXIOV 512
46652  # elif defined(__sun)
46653  /* Solaris (and SunOS?) defines IOV_MAX instead */
46654 @@ -51,105 +51,121 @@
46655  #define LOCAL_BUFFERING 1
46656  #endif
46657  
46658 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq) {
46659 -       chunk *c;
46660 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem) {
46661 +       char * offset;
46662 +       size_t toSend;
46663 +       ssize_t r;
46664 +
46665 +       size_t num_chunks, i;
46666 +       struct iovec chunks[UIO_MAXIOV];
46667 +       chunk *tc; /* transfer chunks */
46668 +       size_t num_bytes = 0;
46669 +
46670 +       /* we can't send more then SSIZE_MAX bytes in one chunk */
46671 +
46672 +       /* build writev list
46673 +        *
46674 +        * 1. limit: num_chunks < UIO_MAXIOV
46675 +        * 2. limit: num_bytes < SSIZE_MAX
46676 +        */
46677 +       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
46678 +
46679 +       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
46680 +               if (tc->mem->used == 0) {
46681 +                       chunks[i].iov_base = tc->mem->ptr;
46682 +                       chunks[i].iov_len  = 0;
46683 +               } else {
46684 +                       offset = tc->mem->ptr + tc->offset;
46685 +                       toSend = tc->mem->used - 1 - tc->offset;
46686 +
46687 +                       chunks[i].iov_base = offset;
46688 +
46689 +                       /* protect the return value of writev() */
46690 +                       if (toSend > SSIZE_MAX ||
46691 +                           num_bytes + toSend > SSIZE_MAX) {
46692 +                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
46693 +
46694 +                               num_chunks = i + 1;
46695 +                               break;
46696 +                       } else {
46697 +                               chunks[i].iov_len = toSend;
46698 +                       }
46699 +
46700 +                       num_bytes += toSend;
46701 +               }
46702 +       }
46703 +
46704 +       if ((r = writev(sock->fd, chunks, num_chunks)) < 0) {
46705 +               switch (errno) {
46706 +               case EAGAIN:
46707 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
46708 +               case EINTR:
46709 +                       return NETWORK_STATUS_INTERRUPTED;
46710 +               case EPIPE:
46711 +               case ECONNRESET:
46712 +                       return NETWORK_STATUS_CONNECTION_CLOSE;
46713 +               default:
46714 +                       log_error_write(srv, __FILE__, __LINE__, "ssd",
46715 +                                       "writev failed:", strerror(errno), sock->fd);
46716 +
46717 +                       return NETWORK_STATUS_FATAL_ERROR;
46718 +               }
46719 +       }
46720 +
46721 +       cq->bytes_out += r;
46722 +
46723 +       /* check which chunks have been written */
46724 +
46725 +       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46726 +               if (r >= (ssize_t)chunks[i].iov_len) {
46727 +                       /* written */
46728 +                       r -= chunks[i].iov_len;
46729 +                       tc->offset += chunks[i].iov_len;
46730 +               } else {
46731 +                       /* partially written */
46732 +
46733 +                       tc->offset += r;
46734 +
46735 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
46736 +               }
46737 +       }
46738 +
46739 +       /* all chunks have been pushed out */
46740 +       return NETWORK_STATUS_SUCCESS;
46741 +}
46742 +
46743 +NETWORK_BACKEND_WRITE(writev) {
46744 +       chunk *c, *tc;
46745         size_t chunks_written = 0;
46746 -       
46747 +
46748         for(c = cq->first; c; c = c->next) {
46749                 int chunk_finished = 0;
46750 -               
46751 +               network_status_t ret;
46752 +
46753                 switch(c->type) {
46754 -               case MEM_CHUNK: {
46755 -                       char * offset;
46756 -                       size_t toSend;
46757 -                       ssize_t r;
46758 -                       
46759 -                       size_t num_chunks, i;
46760 -                       struct iovec chunks[UIO_MAXIOV];
46761 -                       chunk *tc;
46762 -                       size_t num_bytes = 0;
46763 -                       
46764 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
46765 -                       
46766 -                       /* build writev list 
46767 -                        * 
46768 -                        * 1. limit: num_chunks < UIO_MAXIOV
46769 -                        * 2. limit: num_bytes < SSIZE_MAX
46770 -                        */
46771 -                       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
46772 -                       
46773 -                       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
46774 -                               if (tc->mem->used == 0) {
46775 -                                       chunks[i].iov_base = tc->mem->ptr;
46776 -                                       chunks[i].iov_len  = 0;
46777 -                               } else {
46778 -                                       offset = tc->mem->ptr + tc->offset;
46779 -                                       toSend = tc->mem->used - 1 - tc->offset;
46780 -                               
46781 -                                       chunks[i].iov_base = offset;
46782 -                                       
46783 -                                       /* protect the return value of writev() */
46784 -                                       if (toSend > SSIZE_MAX ||
46785 -                                           num_bytes + toSend > SSIZE_MAX) {
46786 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
46787 -                                               
46788 -                                               num_chunks = i + 1;
46789 -                                               break;
46790 -                                       } else {
46791 -                                               chunks[i].iov_len = toSend;
46792 -                                       }
46793 -                                       
46794 -                                       num_bytes += toSend;
46795 -                               }
46796 -                       }
46797 -                       
46798 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
46799 -                               switch (errno) {
46800 -                               case EAGAIN:
46801 -                               case EINTR:
46802 -                                       r = 0;
46803 -                                       break;
46804 -                               case EPIPE:
46805 -                               case ECONNRESET:
46806 -                                       return -2;
46807 -                               default:
46808 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
46809 -                                                       "writev failed:", strerror(errno), fd);
46810 -                               
46811 -                                       return -1;
46812 -                               }
46813 -                       }
46814 -                       
46815 -                       cq->bytes_out += r;
46816 +               case MEM_CHUNK:
46817 +                       ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
46818  
46819 -                       /* check which chunks have been written */
46820 -                       
46821 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46822 -                               if (r >= (ssize_t)chunks[i].iov_len) {
46823 -                                       /* written */
46824 -                                       r -= chunks[i].iov_len;
46825 -                                       tc->offset += chunks[i].iov_len;
46826 -                                       
46827 +                       /* check which chunks are finished now */
46828 +                       for (tc = c; tc; tc = tc->next) {
46829 +                               /* finished the chunk */
46830 +                               if (tc->offset == tc->mem->used - 1) {
46831 +                                       /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
46832                                         if (chunk_finished) {
46833 -                                               /* skip the chunks from further touches */
46834 -                                               chunks_written++;
46835                                                 c = c->next;
46836                                         } else {
46837 -                                               /* chunks_written + c = c->next is done in the for()*/
46838 -                                               chunk_finished++;
46839 +                                               chunk_finished = 1;
46840                                         }
46841                                 } else {
46842 -                                       /* partially written */
46843 -                                       
46844 -                                       tc->offset += r;
46845 -                                       chunk_finished = 0;
46846 -
46847                                         break;
46848                                 }
46849                         }
46850 -                       
46851 +
46852 +                       if (ret != NETWORK_STATUS_SUCCESS) {
46853 +                               return ret;
46854 +                       }
46855 +
46856                         break;
46857 -               }
46858                 case FILE_CHUNK: {
46859                         ssize_t r;
46860                         off_t abs_offset;
46861 @@ -159,26 +175,26 @@
46862  #define KByte * 1024
46863  #define MByte * 1024 KByte
46864  #define GByte * 1024 MByte
46865 -                       const off_t we_want_to_mmap = 512 KByte; 
46866 +                       const off_t we_want_to_mmap = 512 KByte;
46867                         char *start = NULL;
46868  
46869                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46870                                 log_error_write(srv, __FILE__, __LINE__, "sb",
46871                                                 strerror(errno), c->file.name);
46872 -                               return -1;
46873 +                               return NETWORK_STATUS_FATAL_ERROR;
46874                         }
46875  
46876                         abs_offset = c->file.start + c->offset;
46877 -                       
46878 +
46879                         if (abs_offset > sce->st.st_size) {
46880 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
46881 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
46882                                                 "file was shrinked:", c->file.name);
46883 -                               
46884 -                               return -1;
46885 +
46886 +                               return NETWORK_STATUS_FATAL_ERROR;
46887                         }
46888  
46889 -                       /* mmap the buffer 
46890 -                        * - first mmap 
46891 +                       /* mmap the buffer
46892 +                        * - first mmap
46893                          * - new mmap as the we are at the end of the last one */
46894                         if (c->file.mmap.start == MAP_FAILED ||
46895                             abs_offset == (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
46896 @@ -188,7 +204,7 @@
46897                                  * adaptive mem-mapping
46898                                  *   the problem:
46899                                  *     we mmap() the whole file. If someone has alot large files and 32bit
46900 -                                *     machine the virtual address area will be unrun and we will have a failing 
46901 +                                *     machine the virtual address area will be unrun and we will have a failing
46902                                  *     mmap() call.
46903                                  *   solution:
46904                                  *     only mmap 16M in one chunk and move the window as soon as we have finished
46905 @@ -234,8 +250,8 @@
46906                                 if (-1 == c->file.fd) {  /* open the file if not already open */
46907                                         if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
46908                                                 log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno));
46909 -                               
46910 -                                               return -1;
46911 +
46912 +                                               return NETWORK_STATUS_FATAL_ERROR;
46913                                         }
46914  #ifdef FD_CLOEXEC
46915                                         fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
46916 @@ -245,10 +261,10 @@
46917                                 if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
46918                                         /* close it here, otherwise we'd have to set FD_CLOEXEC */
46919  
46920 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:", 
46921 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
46922                                                         strerror(errno), c->file.name, c->file.fd);
46923  
46924 -                                       return -1;
46925 +                                       return NETWORK_STATUS_FATAL_ERROR;
46926                                 }
46927  
46928                                 c->file.mmap.length = to_mmap;
46929 @@ -258,7 +274,7 @@
46930  #ifdef HAVE_MADVISE
46931                                 /* don't advise files < 64Kb */
46932                                 if (c->file.mmap.length > (64 KByte)) {
46933 -                                       /* darwin 7 is returning EINVAL all the time and I don't know how to 
46934 +                                       /* darwin 7 is returning EINVAL all the time and I don't know how to
46935                                          * detect this at runtime.i
46936                                          *
46937                                          * ignore the return value for now */
46938 @@ -274,12 +290,12 @@
46939                         toSend = (c->file.mmap.offset + c->file.mmap.length) - (abs_offset);
46940  
46941                         if (toSend < 0) {
46942 -                               log_error_write(srv, __FILE__, __LINE__, "soooo", 
46943 +                               log_error_write(srv, __FILE__, __LINE__, "soooo",
46944                                                 "toSend is negative:",
46945                                                 toSend,
46946                                                 c->file.mmap.length,
46947                                                 abs_offset,
46948 -                                               c->file.mmap.offset); 
46949 +                                               c->file.mmap.offset);
46950                                 assert(toSend < 0);
46951                         }
46952  
46953 @@ -289,7 +305,7 @@
46954                         start = c->file.mmap.start;
46955  #endif
46956  
46957 -                       if ((r = write(fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
46958 +                       if ((r = write(sock->fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
46959                                 switch (errno) {
46960                                 case EAGAIN:
46961                                 case EINTR:
46962 @@ -297,18 +313,18 @@
46963                                         break;
46964                                 case EPIPE:
46965                                 case ECONNRESET:
46966 -                                       return -2;
46967 +                                       return NETWORK_STATUS_CONNECTION_CLOSE;
46968                                 default:
46969 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
46970 -                                                       "write failed:", strerror(errno), fd);
46971 -                                       
46972 -                                       return -1;
46973 +                                       log_error_write(srv, __FILE__, __LINE__, "ssd",
46974 +                                                       "write failed:", strerror(errno), sock->fd);
46975 +
46976 +                                       return NETWORK_STATUS_FATAL_ERROR;
46977                                 }
46978                         }
46979 -                       
46980 +
46981                         c->offset += r;
46982                         cq->bytes_out += r;
46983 -                       
46984 +
46985                         if (c->offset == c->file.length) {
46986                                 chunk_finished = 1;
46987  
46988 @@ -318,26 +334,26 @@
46989                                         c->file.mmap.start = MAP_FAILED;
46990                                 }
46991                         }
46992 -                       
46993 +
46994                         break;
46995                 }
46996                 default:
46997 -                       
46998 +
46999                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
47000 -                       
47001 -                       return -1;
47002 +
47003 +                       return NETWORK_STATUS_FATAL_ERROR;
47004                 }
47005 -               
47006 +
47007                 if (!chunk_finished) {
47008                         /* not finished yet */
47009 -                       
47010 +
47011                         break;
47012                 }
47013 -               
47014 +
47015                 chunks_written++;
47016         }
47017  
47018 -       return chunks_written;
47019 +       return NETWORK_STATUS_SUCCESS;
47020  }
47021  
47022  #endif
47023 --- ../lighttpd-1.4.11/src/plugin.c     2006-02-08 14:00:54.000000000 +0200
47024 +++ lighttpd-1.4.12/src/plugin.c        2006-07-16 00:26:04.000000000 +0300
47025 @@ -13,27 +13,27 @@
47026  #include <valgrind/valgrind.h>
47027  #endif
47028  
47029 -#ifndef __WIN32
47030 +#ifndef _WIN32
47031  #include <dlfcn.h>
47032  #endif
47033  /*
47034 - * 
47035 + *
47036   * if you change this enum to add a new callback, be sure
47037   * - that PLUGIN_FUNC_SIZEOF is the last entry
47038   * - that you add PLUGIN_TO_SLOT twice:
47039 - *   1. as callback-dispatcher 
47040 + *   1. as callback-dispatcher
47041   *   2. in plugins_call_init()
47042 - * 
47043 + *
47044   */
47045  
47046  typedef struct {
47047         PLUGIN_DATA;
47048  } plugin_data;
47049  
47050 -typedef enum { 
47051 +typedef enum {
47052         PLUGIN_FUNC_UNSET,
47053 -               PLUGIN_FUNC_HANDLE_URI_CLEAN, 
47054 -               PLUGIN_FUNC_HANDLE_URI_RAW, 
47055 +               PLUGIN_FUNC_HANDLE_URI_CLEAN,
47056 +               PLUGIN_FUNC_HANDLE_URI_RAW,
47057                 PLUGIN_FUNC_HANDLE_REQUEST_DONE,
47058                 PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
47059                 PLUGIN_FUNC_HANDLE_TRIGGER,
47060 @@ -44,38 +44,42 @@
47061                 PLUGIN_FUNC_HANDLE_DOCROOT,
47062                 PLUGIN_FUNC_HANDLE_PHYSICAL,
47063                 PLUGIN_FUNC_CONNECTION_RESET,
47064 -               PLUGIN_FUNC_INIT, 
47065 +               PLUGIN_FUNC_INIT,
47066                 PLUGIN_FUNC_CLEANUP,
47067                 PLUGIN_FUNC_SET_DEFAULTS,
47068 -               
47069 +
47070                 PLUGIN_FUNC_SIZEOF
47071  } plugin_t;
47072  
47073  static plugin *plugin_init(void) {
47074         plugin *p;
47075 -       
47076 +
47077         p = calloc(1, sizeof(*p));
47078 -       
47079 +
47080 +       p->required_plugins = array_init();
47081 +
47082         return p;
47083  }
47084  
47085  static void plugin_free(plugin *p) {
47086         int use_dlclose = 1;
47087         if (p->name) buffer_free(p->name);
47088 +
47089 +       array_free(p->required_plugins);
47090  #ifdef HAVE_VALGRIND_VALGRIND_H
47091         /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
47092  #endif
47093  
47094  #ifndef LIGHTTPD_STATIC
47095 -       if (use_dlclose && p->lib) {    
47096 -#ifdef __WIN32
47097 +       if (use_dlclose && p->lib) {
47098 +#ifdef _WIN32
47099                 FreeLibrary(p->lib);
47100  #else
47101                 dlclose(p->lib);
47102  #endif
47103         }
47104  #endif
47105 -               
47106 +
47107         free(p);
47108  }
47109  
47110 @@ -89,17 +93,17 @@
47111                 srv->plugins.size += 4;
47112                 srv->plugins.ptr   = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
47113         }
47114 -       
47115 +
47116         ps = srv->plugins.ptr;
47117         ps[srv->plugins.used++] = p;
47118 -       
47119 +
47120         return 0;
47121  }
47122  
47123  /**
47124 - * 
47125 - * 
47126 - * 
47127 + *
47128 + *
47129 + *
47130   */
47131  
47132  #ifdef LIGHTTPD_STATIC
47133 @@ -121,30 +125,35 @@
47134  #else
47135  int plugins_load(server *srv) {
47136         plugin *p;
47137 +#ifdef _WIN32
47138 +    FARPROC init;
47139 +#else
47140         int (*init)(plugin *pl);
47141 +#endif
47142 +
47143         const char *error;
47144 -       size_t i;
47145 -       
47146 +       size_t i, j, k;
47147 +
47148         for (i = 0; i < srv->srvconf.modules->used; i++) {
47149                 data_string *d = (data_string *)srv->srvconf.modules->data[i];
47150                 char *modules = d->value->ptr;
47151 -       
47152 +
47153                 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
47154  
47155                 buffer_append_string(srv->tmp_buf, "/");
47156                 buffer_append_string(srv->tmp_buf, modules);
47157 -#if defined(__WIN32) || defined(__CYGWIN__)
47158 +#if defined(_WIN32) || defined(__CYGWIN__)
47159                 buffer_append_string(srv->tmp_buf, ".dll");
47160  #else
47161                 buffer_append_string(srv->tmp_buf, ".so");
47162  #endif
47163 -       
47164 +
47165                 p = plugin_init();
47166 -#ifdef __WIN32
47167 +#ifdef _WIN32
47168                 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
47169                         LPVOID lpMsgBuf;
47170                         FormatMessage(
47171 -                               FORMAT_MESSAGE_ALLOCATE_BUFFER | 
47172 +                               FORMAT_MESSAGE_ALLOCATE_BUFFER |
47173                                 FORMAT_MESSAGE_FROM_SYSTEM,
47174                                 NULL,
47175                                 GetLastError(),
47176 @@ -152,36 +161,36 @@
47177                                 (LPTSTR) &lpMsgBuf,
47178                                 0, NULL );
47179  
47180 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed", 
47181 +                       log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
47182                                         lpMsgBuf, srv->tmp_buf);
47183 -                       
47184 +
47185                         plugin_free(p);
47186 -                       
47187 +
47188                         return -1;
47189  
47190                 }
47191 -#else  
47192 +#else
47193                 if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_LAZY))) {
47194 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:", 
47195 +                       log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
47196                                         srv->tmp_buf, dlerror());
47197 -                       
47198 +
47199                         plugin_free(p);
47200 -                       
47201 +
47202                         return -1;
47203                 }
47204 -               
47205 +
47206  #endif
47207                 buffer_reset(srv->tmp_buf);
47208                 buffer_copy_string(srv->tmp_buf, modules);
47209                 buffer_append_string(srv->tmp_buf, "_plugin_init");
47210  
47211 -#ifdef __WIN32
47212 +#ifdef _WIN32
47213                 init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
47214  
47215                 if (init == NULL)  {
47216                         LPVOID lpMsgBuf;
47217                         FormatMessage(
47218 -                               FORMAT_MESSAGE_ALLOCATE_BUFFER | 
47219 +                               FORMAT_MESSAGE_ALLOCATE_BUFFER |
47220                                 FORMAT_MESSAGE_FROM_SYSTEM,
47221                                 NULL,
47222                                 GetLastError(),
47223 @@ -190,7 +199,7 @@
47224                                 0, NULL );
47225  
47226                         log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
47227 -                       
47228 +
47229                         plugin_free(p);
47230                         return -1;
47231                 }
47232 @@ -203,24 +212,43 @@
47233  #endif
47234                 if ((error = dlerror()) != NULL)  {
47235                         log_error_write(srv, __FILE__, __LINE__, "s", error);
47236 -                       
47237 +
47238                         plugin_free(p);
47239                         return -1;
47240                 }
47241 -       
47242 +
47243  #endif
47244                 if ((*init)(p)) {
47245                         log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin init failed" );
47246 -                       
47247 +
47248                         plugin_free(p);
47249                         return -1;
47250                 }
47251  #if 0
47252                 log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin loaded" );
47253  #endif
47254 +               /* check if the required plugin is loaded */
47255 +               for (k = 0; k < p->required_plugins->used; k++) {
47256 +                       data_string *req = (data_string *)p->required_plugins->data[k];
47257 +
47258 +                       for (j = 0; j < i; j++) {
47259 +                               data_string *mod = (data_string *)srv->srvconf.modules->data[j];
47260 +
47261 +                               if (buffer_is_equal(req->value, mod->value)) break;
47262 +                       }
47263 +
47264 +                       if (j == i) {
47265 +                               /* not found */
47266 +                               log_error_write(srv, __FILE__, __LINE__, "ssbs", modules, "failed to load. required plugin", req->value, "was not loaded" );
47267 +
47268 +                               plugin_free(p);
47269 +                       
47270 +                               return -1;
47271 +                       }
47272 +               }
47273                 plugins_register(srv, p);
47274         }
47275 -       
47276 +
47277         return 0;
47278  }
47279  #endif
47280 @@ -253,8 +281,8 @@
47281         }
47282  
47283  /**
47284 - * plugins that use 
47285 - * 
47286 + * plugins that use
47287 + *
47288   * - server *srv
47289   * - connection *con
47290   * - void *p_d (plugin_data *)
47291 @@ -301,12 +329,12 @@
47292         }
47293  
47294  /**
47295 - * plugins that use 
47296 - * 
47297 + * plugins that use
47298 + *
47299   * - server *srv
47300   * - void *p_d (plugin_data *)
47301   */
47302 -                                                                       
47303 +
47304  PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
47305  PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
47306  PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
47307 @@ -314,18 +342,18 @@
47308  
47309  #undef PLUGIN_TO_SLOT
47310  
47311 -#if 0                                                                  
47312 +#if 0
47313  /**
47314 - * 
47315 + *
47316   * special handler
47317 - * 
47318 + *
47319   */
47320  handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
47321         size_t i;
47322         plugin **ps;
47323 -       
47324 +
47325         ps = srv->plugins.ptr;
47326 -       
47327 +
47328         for (i = 0; i < srv->plugins.used; i++) {
47329                 plugin *p = ps[i];
47330                 if (p->handle_fdevent) {
47331 @@ -344,34 +372,34 @@
47332                         }
47333                 }
47334         }
47335 -       
47336 +
47337         return HANDLER_GO_ON;
47338  }
47339  #endif
47340  /**
47341 - * 
47342 + *
47343   * - call init function of all plugins to init the plugin-internals
47344   * - added each plugin that supports has callback to the corresponding slot
47345 - * 
47346 + *
47347   * - is only called once.
47348   */
47349  
47350  handler_t plugins_call_init(server *srv) {
47351         size_t i;
47352         plugin **ps;
47353 -       
47354 +
47355         ps = srv->plugins.ptr;
47356 -       
47357 +
47358         /* fill slots */
47359 -       
47360 +
47361         srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
47362 -       
47363 +
47364         for (i = 0; i < srv->plugins.used; i++) {
47365                 size_t j;
47366                 /* check which calls are supported */
47367 -               
47368 +
47369                 plugin *p = ps[i];
47370 -               
47371 +
47372  #define PLUGIN_TO_SLOT(x, y) \
47373         if (p->y) { \
47374                 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
47375 @@ -384,11 +412,11 @@
47376                         slot[j] = p;\
47377                         break;\
47378                 }\
47379 -       } 
47380 -               
47381 -               
47382 -               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean); 
47383 -               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw); 
47384 +       }
47385 +
47386 +
47387 +               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
47388 +               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
47389                 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
47390                 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
47391                 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
47392 @@ -402,19 +430,19 @@
47393                 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
47394                 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
47395  #undef PLUGIN_TO_SLOT
47396 -               
47397 +
47398                 if (p->init) {
47399                         if (NULL == (p->data = p->init())) {
47400 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
47401 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
47402                                                 "plugin-init failed for module", p->name);
47403                                 return HANDLER_ERROR;
47404                         }
47405 -                       
47406 +
47407                         /* used for con->mode, DIRECT == 0, plugins above that */
47408                         ((plugin_data *)(p->data))->id = i + 1;
47409 -                       
47410 +
47411                         if (p->version != LIGHTTPD_VERSION_ID) {
47412 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
47413 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
47414                                                 "plugin-version doesn't match lighttpd-version for", p->name);
47415                                 return HANDLER_ERROR;
47416                         }
47417 @@ -422,29 +450,46 @@
47418                         p->data = NULL;
47419                 }
47420         }
47421 -       
47422 +
47423         return HANDLER_GO_ON;
47424  }
47425  
47426 +/**
47427 + * get the config-storage of the named plugin 
47428 + */
47429 +void *plugin_get_config(server *srv, const char *name) {
47430 +       size_t i;
47431 +
47432 +       for (i = 0; i < srv->plugins.used; i++) {
47433 +               plugin *p = ((plugin **)srv->plugins.ptr)[i];
47434 +
47435 +               if (buffer_is_equal_string(p->name, name, strlen(name))) {
47436 +                       return p->data;
47437 +               }
47438 +       }
47439 +
47440 +       return NULL;
47441 +}
47442 +
47443  void plugins_free(server *srv) {
47444         size_t i;
47445         plugins_call_cleanup(srv);
47446 -       
47447 +
47448         for (i = 0; i < srv->plugins.used; i++) {
47449                 plugin *p = ((plugin **)srv->plugins.ptr)[i];
47450 -               
47451 +
47452                 plugin_free(p);
47453         }
47454 -       
47455 +
47456         for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
47457                 plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
47458 -               
47459 +
47460                 if (slot) free(slot);
47461         }
47462 -       
47463 +
47464         free(srv->plugin_slots);
47465         srv->plugin_slots = NULL;
47466 -       
47467 +
47468         free(srv->plugins.ptr);
47469         srv->plugins.ptr = NULL;
47470         srv->plugins.used = 0;
47471 --- ../lighttpd-1.4.11/src/plugin.h     2005-08-15 12:28:56.000000000 +0300
47472 +++ lighttpd-1.4.12/src/plugin.h        2006-07-16 00:26:04.000000000 +0300
47473 @@ -12,6 +12,12 @@
47474  
47475  #define INIT_FUNC(x) \
47476                 static void *x()
47477 +/*
47478 + * The PATCH_OPTION() macro is used in the patch_connection() functions
47479 + * of the modules to update the config object for the current request.
47480 + */
47481 +#define PATCH_OPTION(x) \
47482 +               p->conf.x = s->x
47483  
47484  #define FREE_FUNC          SERVER_FUNC
47485  #define TRIGGER_FUNC       SERVER_FUNC
47486 @@ -25,19 +31,19 @@
47487  #define URIHANDLER_FUNC    CONNECTION_FUNC
47488  
47489  #define PLUGIN_DATA        size_t id
47490 -                                                                                                                                               
47491 +
47492  typedef struct {
47493         size_t version;
47494 -       
47495 +
47496         buffer *name; /* name of the plugin */
47497 -       
47498 +
47499         void *(* init)                       ();
47500         handler_t (* set_defaults)           (server *srv, void *p_d);
47501         handler_t (* cleanup)                (server *srv, void *p_d);
47502                                                                                            /* is called ... */
47503         handler_t (* handle_trigger)         (server *srv, void *p_d);                     /* once a second */
47504         handler_t (* handle_sighup)          (server *srv, void *p_d);                     /* at a signup */
47505 -       
47506 +
47507         handler_t (* handle_uri_raw)         (server *srv, connection *con, void *p_d);    /* after uri_raw is set */
47508         handler_t (* handle_uri_clean)       (server *srv, connection *con, void *p_d);    /* after uri is set */
47509         handler_t (* handle_docroot)         (server *srv, connection *con, void *p_d);    /* getting the document-root */
47510 @@ -45,20 +51,22 @@
47511         handler_t (* handle_request_done)    (server *srv, connection *con, void *p_d);    /* at the end of a request */
47512         handler_t (* handle_connection_close)(server *srv, connection *con, void *p_d);    /* at the end of a connection */
47513         handler_t (* handle_joblist)         (server *srv, connection *con, void *p_d);    /* after all events are handled */
47514 -       
47515 -       
47516 -       
47517 -       handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);   
47518 -       
47519 -                                                                                          /* when a handler for the request 
47520 +
47521 +
47522 +
47523 +       handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);
47524 +
47525 +                                                                                          /* when a handler for the request
47526                                                                                             * has to be found
47527                                                                                             */
47528         handler_t (* handle_subrequest)      (server *srv, connection *con, void *p_d);    /* */
47529         handler_t (* connection_reset)       (server *srv, connection *con, void *p_d);    /* */
47530         void *data;
47531 -       
47532 +
47533         /* dlopen handle */
47534         void *lib;
47535 +
47536 +       array *required_plugins;
47537  } plugin;
47538  
47539  int plugins_load(server *srv);
47540 @@ -88,5 +96,8 @@
47541  int config_patch_connection(server *srv, connection *con, comp_key_t comp);
47542  int config_check_cond(server *srv, connection *con, data_config *dc);
47543  int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n);
47544 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result);
47545 +
47546 +void *plugin_get_config(server *srv, const char *name);
47547  
47548  #endif
47549 --- ../lighttpd-1.4.11/src/proc_open.c  2005-08-11 01:26:39.000000000 +0300
47550 +++ lighttpd-1.4.12/src/proc_open.c     2006-07-16 00:26:04.000000000 +0300
47551 @@ -13,13 +13,13 @@
47552  #endif
47553  
47554  
47555 -#ifdef WIN32
47556 +#ifdef _WIN32
47557  /* {{{ win32 stuff */
47558  # define SHELLENV "ComSpec"
47559  # define SECURITY_DC , SECURITY_ATTRIBUTES *security
47560  # define SECURITY_CC , security
47561  # define pipe(pair) (CreatePipe(&pair[0], &pair[1], security, 2048L) ? 0 : -1)
47562 -static inline HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
47563 +static HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
47564  {
47565         HANDLE copy, self = GetCurrentProcess();
47566  
47567 @@ -148,11 +148,14 @@
47568         STARTUPINFO si;
47569         BOOL procok;
47570         SECURITY_ATTRIBUTES security;
47571 -       const char *shell;
47572 +       const char *shell = NULL;
47573 +       const char *windir = NULL;
47574         buffer *cmdline;
47575  
47576 -       if (NULL == (shell = getenv(SHELLENV))) {
47577 -               fprintf(stderr, "env %s is required", SHELLENV);
47578 +       if (NULL == (shell = getenv(SHELLENV)) &&
47579 +                       NULL == (windir = getenv("SystemRoot")) &&
47580 +                       NULL == (windir = getenv("windir"))) {
47581 +               fprintf(stderr, "One of %s,%%SystemRoot,%%windir is required", SHELLENV);
47582                 return -1;
47583         }
47584  
47585 @@ -177,17 +180,23 @@
47586         memset(&pi, 0, sizeof(pi));
47587  
47588         cmdline = buffer_init();
47589 -       buffer_append_string(cmdline, shell);
47590 +       if (shell) {
47591 +               buffer_append_string(cmdline, shell);
47592 +       } else {
47593 +               buffer_append_string(cmdline, windir);
47594 +               buffer_append_string(cmdline, "\\system32\\cmd.exe");
47595 +       }
47596         buffer_append_string_len(cmdline, CONST_STR_LEN(" /c "));
47597         buffer_append_string(cmdline, command);
47598         procok = CreateProcess(NULL, cmdline->ptr, &security, &security, TRUE,
47599                         NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
47600 -       buffer_free(cmdline);
47601  
47602         if (FALSE == procok) {
47603 -               fprintf(stderr, "failed to CreateProcess");
47604 +               fprintf(stderr, "failed to CreateProcess: %s", cmdline->ptr);
47605 +               buffer_free(cmdline);
47606                 return -1;
47607         }
47608 +       buffer_free(cmdline);
47609  
47610         proc->child = pi.hProcess;
47611         CloseHandle(pi.hThread);
47612 @@ -226,8 +235,7 @@
47613         const char *shell;
47614  
47615         if (NULL == (shell = getenv(SHELLENV))) {
47616 -               fprintf(stderr, "env %s is required", SHELLENV);
47617 -               return -1;
47618 +               shell = "/bin/sh";
47619         }
47620  
47621         if (proc_open_pipes(proc) != 0) {
47622 @@ -262,11 +270,11 @@
47623         }
47624  }
47625  /* }}} */
47626 -#endif /* WIN32 */
47627 +#endif /* _WIN32 */
47628  
47629  /* {{{ proc_read_fd_to_buffer */
47630  static void proc_read_fd_to_buffer(int fd, buffer *b) {
47631 -       ssize_t s;
47632 +       int s; /* win32 has not ssize_t */
47633  
47634         for (;;) {
47635                 buffer_prepare_append(b, 512);
47636 --- ../lighttpd-1.4.11/src/proc_open.h  2005-08-11 01:26:39.000000000 +0300
47637 +++ lighttpd-1.4.12/src/proc_open.h     2006-07-16 00:26:04.000000000 +0300
47638 @@ -1,7 +1,7 @@
47639  
47640  #include "buffer.h"
47641  
47642 -#ifdef WIN32
47643 +#ifdef _WIN32
47644  #include <windows.h>
47645  typedef HANDLE descriptor_t;
47646  typedef HANDLE proc_pid_t;
47647 --- ../lighttpd-1.4.11/src/request.c    2006-03-05 11:58:09.000000000 +0200
47648 +++ lighttpd-1.4.12/src/request.c       2006-07-18 13:03:40.000000000 +0300
47649 @@ -10,15 +10,17 @@
47650  #include "keyvalue.h"
47651  #include "log.h"
47652  
47653 +#include "sys-strings.h"
47654 +
47655  static int request_check_hostname(server *srv, connection *con, buffer *host) {
47656         enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
47657         size_t i;
47658         int label_len = 0;
47659         size_t host_len;
47660         char *colon;
47661 -       int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */ 
47662 +       int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
47663         int level = 0;
47664 -       
47665 +
47666         UNUSED(srv);
47667         UNUSED(con);
47668  
47669 @@ -32,17 +34,17 @@
47670          *       IPv6address   = "[" ... "]"
47671          *       port          = *digit
47672          */
47673 -       
47674 +
47675         /* no Host: */
47676         if (!host || host->used == 0) return 0;
47677 -       
47678 +
47679         host_len = host->used - 1;
47680 -       
47681 +
47682         /* IPv6 adress */
47683         if (host->ptr[0] == '[') {
47684                 char *c = host->ptr + 1;
47685                 int colon_cnt = 0;
47686 -               
47687 +
47688                 /* check portnumber */
47689                 for (; *c && *c != ']'; c++) {
47690                         if (*c == ':') {
47691 @@ -53,12 +55,12 @@
47692                                 return -1;
47693                         }
47694                 }
47695 -               
47696 +
47697                 /* missing ] */
47698                 if (!*c) {
47699                         return -1;
47700                 }
47701 -               
47702 +
47703                 /* check port */
47704                 if (*(c+1) == ':') {
47705                         for (c += 2; *c; c++) {
47706 @@ -69,39 +71,39 @@
47707                 }
47708                 return 0;
47709         }
47710 -       
47711 +
47712         if (NULL != (colon = memchr(host->ptr, ':', host_len))) {
47713                 char *c = colon + 1;
47714 -               
47715 +
47716                 /* check portnumber */
47717                 for (; *c; c++) {
47718                         if (!light_isdigit(*c)) return -1;
47719                 }
47720 -               
47721 +
47722                 /* remove the port from the host-len */
47723                 host_len = colon - host->ptr;
47724         }
47725 -       
47726 +
47727         /* Host is empty */
47728         if (host_len == 0) return -1;
47729 -       
47730 +
47731         /* scan from the right and skip the \0 */
47732         for (i = host_len - 1; i + 1 > 0; i--) {
47733                 const char c = host->ptr[i];
47734  
47735                 switch (stage) {
47736 -               case TOPLABEL: 
47737 +               case TOPLABEL:
47738                         if (c == '.') {
47739                                 /* only switch stage, if this is not the last character */
47740                                 if (i != host_len - 1) {
47741                                         if (label_len == 0) {
47742                                                 return -1;
47743                                         }
47744 -                                       
47745 +
47746                                         /* check the first character at right of the dot */
47747                                         if (is_ip == 0) {
47748                                                 if (!light_isalpha(host->ptr[i+1])) {
47749 -                                                       return -1; 
47750 +                                                       return -1;
47751                                                 }
47752                                         } else if (!light_isdigit(host->ptr[i+1])) {
47753                                                 is_ip = 0;
47754 @@ -111,9 +113,9 @@
47755                                                 /* just digits */
47756                                                 is_ip = 1;
47757                                         }
47758 -                                               
47759 +
47760                                         stage = DOMAINLABEL;
47761 -                                       
47762 +
47763                                         label_len = 0;
47764                                         level++;
47765                                 } else if (i == 0) {
47766 @@ -135,7 +137,7 @@
47767                                 }
47768                                 label_len++;
47769                         }
47770 -                       
47771 +
47772                         break;
47773                 case DOMAINLABEL:
47774                         if (is_ip == 1) {
47775 @@ -143,7 +145,7 @@
47776                                         if (label_len == 0) {
47777                                                 return -1;
47778                                         }
47779 -                                       
47780 +
47781                                         label_len = 0;
47782                                         level++;
47783                                 } else if (!light_isdigit(c)) {
47784 @@ -156,12 +158,12 @@
47785                                         if (label_len == 0) {
47786                                                 return -1;
47787                                         }
47788 -                                       
47789 +
47790                                         /* c is either - or alphanum here */
47791                                         if ('-' == host->ptr[i+1]) {
47792                                                 return -1;
47793                                         }
47794 -                                       
47795 +
47796                                         label_len = 0;
47797                                         level++;
47798                                 } else if (i == 0) {
47799 @@ -176,20 +178,20 @@
47800                                         label_len++;
47801                                 }
47802                         }
47803 -                       
47804 +
47805                         break;
47806                 }
47807         }
47808 -       
47809 +
47810         /* a IP has to consist of 4 parts */
47811         if (is_ip == 1 && level != 3) {
47812                 return -1;
47813         }
47814 -       
47815 +
47816         if (label_len == 0) {
47817                 return -1;
47818         }
47819 -       
47820 +
47821         return 0;
47822  }
47823  
47824 @@ -201,53 +203,53 @@
47825         char *s;
47826         size_t i;
47827         int state = 0;
47828 -       /*  
47829 -        * parse 
47830 -        * 
47831 +       /*
47832 +        * parse
47833 +        *
47834          * val1, val2, val3, val4
47835 -        * 
47836 +        *
47837          * into a array (more or less a explode() incl. striping of whitespaces
47838          */
47839 -       
47840 +
47841         if (b->used == 0) return 0;
47842 -       
47843 +
47844         s = b->ptr;
47845 -       
47846 +
47847         for (i =0; i < b->used - 1; ) {
47848                 char *start = NULL, *end = NULL;
47849                 data_string *ds;
47850 -               
47851 +
47852                 switch (state) {
47853                 case 0: /* ws */
47854 -                       
47855 +
47856                         /* skip ws */
47857                         for (; (*s == ' ' || *s == '\t') && i < b->used - 1; i++, s++);
47858 -                       
47859 -                       
47860 +
47861 +
47862                         state = 1;
47863                         break;
47864                 case 1: /* value */
47865                         start = s;
47866 -                       
47867 +
47868                         for (; *s != ',' && i < b->used - 1; i++, s++);
47869                         end = s - 1;
47870 -                       
47871 +
47872                         for (; (*end == ' ' || *end == '\t') && end > start; end--);
47873 -                       
47874 +
47875                         if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
47876                                 ds = data_string_init();
47877                         }
47878  
47879                         buffer_copy_string_len(ds->value, start, end-start+1);
47880                         array_insert_unique(vals, (data_unset *)ds);
47881 -                       
47882 +
47883                         if (*s == ',') {
47884                                 state = 0;
47885                                 i++;
47886                                 s++;
47887                         } else {
47888                                 /* end of string */
47889 -                               
47890 +
47891                                 state = 2;
47892                         }
47893                         break;
47894 @@ -263,7 +265,7 @@
47895         if (c <= 32) return 0;
47896         if (c == 127) return 0;
47897         if (c == 255) return 0;
47898 -       
47899 +
47900         return 1;
47901  }
47902  
47903 @@ -271,28 +273,28 @@
47904         char *uri = NULL, *proto = NULL, *method = NULL, con_length_set;
47905         int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding;
47906         char *value = NULL, *key = NULL;
47907 -       
47908 +
47909         enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_KEEPALIVE, HTTP_CONNECTION_CLOSE } keep_alive_set = HTTP_CONNECTION_UNSET;
47910 -       
47911 +
47912         int line = 0;
47913 -       
47914 +
47915         int request_line_stage = 0;
47916         size_t i, first;
47917 -       
47918 +
47919         int done = 0;
47920 -       
47921 +
47922         data_string *ds = NULL;
47923 -       
47924 -       /* 
47925 -        * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$" 
47926 -        * Option : "^([-a-zA-Z]+): (.+)$"                    
47927 +
47928 +       /*
47929 +        * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
47930 +        * Option : "^([-a-zA-Z]+): (.+)$"
47931          * End    : "^$"
47932          */
47933  
47934         if (con->conf.log_request_header) {
47935 -               log_error_write(srv, __FILE__, __LINE__, "sdsdSb", 
47936 -                               "fd:", con->fd, 
47937 -                               "request-len:", con->request.request->used, 
47938 +               log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
47939 +                               "fd:", con->sock->fd,
47940 +                               "request-len:", con->request.request->used,
47941                                 "\n", con->request.request);
47942         }
47943  
47944 @@ -300,13 +302,13 @@
47945             con->request.request->ptr[0] == '\r' &&
47946             con->request.request->ptr[1] == '\n') {
47947                 /* we are in keep-alive and might get \r\n after a previous POST request.*/
47948 -               
47949 +
47950                 buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, con->request.request->used - 1 - 2);
47951         } else {
47952                 /* fill the local request buffer */
47953                 buffer_copy_string_buffer(con->parse_request, con->request.request);
47954         }
47955 -       
47956 +
47957         keep_alive_set = 0;
47958         con_length_set = 0;
47959  
47960 @@ -318,25 +320,25 @@
47961          * */
47962         for (i = 0, first = 0; i < con->parse_request->used && line == 0; i++) {
47963                 char *cur = con->parse_request->ptr + i;
47964 -               
47965 +
47966                 switch(*cur) {
47967 -               case '\r': 
47968 +               case '\r':
47969                         if (con->parse_request->ptr[i+1] == '\n') {
47970                                 http_method_t r;
47971                                 char *nuri = NULL;
47972                                 size_t j;
47973 -                               
47974 +
47975                                 /* \r\n -> \0\0 */
47976                                 con->parse_request->ptr[i] = '\0';
47977                                 con->parse_request->ptr[i+1] = '\0';
47978 -                               
47979 +
47980                                 buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
47981 -                               
47982 +
47983                                 if (request_line_stage != 2) {
47984                                         con->http_status = 400;
47985                                         con->response.keep_alive = 0;
47986                                         con->keep_alive = 0;
47987 -                                       
47988 +
47989                                         if (srv->srvconf.log_request_header_on_error) {
47990                                                 log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
47991                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
47992 @@ -345,36 +347,36 @@
47993                                         }
47994                                         return 0;
47995                                 }
47996 -                               
47997 +
47998                                 proto = con->parse_request->ptr + first;
47999 -                               
48000 +
48001                                 *(uri - 1) = '\0';
48002                                 *(proto - 1) = '\0';
48003 -                               
48004 +
48005                                 /* we got the first one :) */
48006                                 if (-1 == (r = get_http_method_key(method))) {
48007                                         con->http_status = 501;
48008                                         con->response.keep_alive = 0;
48009                                         con->keep_alive = 0;
48010 -                                       
48011 +
48012                                         if (srv->srvconf.log_request_header_on_error) {
48013                                                 log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
48014                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48015                                                                 "request-header:\n",
48016                                                                 con->request.request);
48017                                         }
48018 -                               
48019 +
48020                                         return 0;
48021                                 }
48022 -                               
48023 +
48024                                 con->request.http_method = r;
48025 -                       
48026 -                               /* 
48027 +
48028 +                               /*
48029                                  * RFC2616 says:
48030                                  *
48031                                  * HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT
48032                                  *
48033 -                                * */   
48034 +                                * */
48035                                 if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) {
48036                                         char * major = proto + sizeof("HTTP/") - 1;
48037                                         char * minor = strchr(major, '.');
48038 @@ -413,10 +415,10 @@
48039                                         }
48040  
48041                                         if (major_num == 1 && minor_num == 1) {
48042 -                                               con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0;
48043 +                                               con->request.http_version = HTTP_VERSION_1_1;
48044                                         } else if (major_num == 1 && minor_num == 0) {
48045                                                 con->request.http_version = HTTP_VERSION_1_0;
48046 -                                       } else { 
48047 +                                       } else {
48048                                                 con->http_status = 505;
48049  
48050                                                 if (srv->srvconf.log_request_header_on_error) {
48051 @@ -439,30 +441,30 @@
48052                                         }
48053                                         return 0;
48054                                 }
48055 -                               
48056 +
48057                                 if (0 == strncmp(uri, "http://", 7) &&
48058                                     NULL != (nuri = strchr(uri + 7, '/'))) {
48059                                         /* ignore the host-part */
48060 -                                       
48061 +
48062                                         buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
48063                                 } else {
48064                                         /* everything looks good so far */
48065                                         buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
48066                                 }
48067 -                               
48068 +
48069                                 /* check uri for invalid characters */
48070                                 for (j = 0; j < con->request.uri->used - 1; j++) {
48071                                         if (!request_uri_is_valid_char(con->request.uri->ptr[j])) {
48072                                                 unsigned char buf[2];
48073                                                 con->http_status = 400;
48074                                                 con->keep_alive = 0;
48075 -                                               
48076 +
48077                                                 if (srv->srvconf.log_request_header_on_error) {
48078                                                         buf[0] = con->request.uri->ptr[j];
48079                                                         buf[1] = '\0';
48080 -                                       
48081 +
48082                                                         if (con->request.uri->ptr[j] > 32 &&
48083 -                                                           con->request.uri->ptr[j] != 127) {  
48084 +                                                           con->request.uri->ptr[j] != 127) {
48085                                                                 /* the character is printable -> print it */
48086                                                                 log_error_write(srv, __FILE__, __LINE__, "ss",
48087                                                                                 "invalid character in URI -> 400",
48088 @@ -473,20 +475,20 @@
48089                                                                                 "invalid character in URI -> 400",
48090                                                                                 con->request.uri->ptr[j]);
48091                                                         }
48092 -                                               
48093 +
48094                                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
48095                                                                         "request-header:\n",
48096                                                                         con->request.request);
48097                                                 }
48098 -                                               
48099 +
48100                                                 return 0;
48101                                         }
48102                                 }
48103 -                               
48104 +
48105                                 buffer_copy_string_buffer(con->request.orig_uri, con->request.uri);
48106 -                               
48107 +
48108                                 con->http_status = 0;
48109 -                               
48110 +
48111                                 i++;
48112                                 line++;
48113                                 first = i+1;
48114 @@ -494,14 +496,14 @@
48115                         break;
48116                 case ' ':
48117                         switch(request_line_stage) {
48118 -                       case 0: 
48119 +                       case 0:
48120                                 /* GET|POST|... */
48121 -                               method = con->parse_request->ptr + first; 
48122 +                               method = con->parse_request->ptr + first;
48123                                 first = i + 1;
48124                                 break;
48125                         case 1:
48126                                 /* /foobar/... */
48127 -                               uri = con->parse_request->ptr + first; 
48128 +                               uri = con->parse_request->ptr + first;
48129                                 first = i + 1;
48130                                 break;
48131                         default:
48132 @@ -509,7 +511,7 @@
48133                                 con->http_status = 400;
48134                                 con->response.keep_alive = 0;
48135                                 con->keep_alive = 0;
48136 -                               
48137 +
48138                                 if (srv->srvconf.log_request_header_on_error) {
48139                                         log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
48140                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
48141 @@ -518,12 +520,12 @@
48142                                 }
48143                                 return 0;
48144                         }
48145 -                       
48146 +
48147                         request_line_stage++;
48148                         break;
48149                 }
48150         }
48151 -       
48152 +
48153         in_folding = 0;
48154  
48155         if (con->request.uri->used == 1) {
48156 @@ -540,30 +542,30 @@
48157                 return 0;
48158         }
48159  
48160 -       
48161 +
48162         for (; i < con->parse_request->used && !done; i++) {
48163                 char *cur = con->parse_request->ptr + i;
48164 -               
48165 +
48166                 if (is_key) {
48167                         size_t j;
48168                         int got_colon = 0;
48169 -                       
48170 +
48171                         /**
48172                          * 1*<any CHAR except CTLs or separators>
48173                          * CTLs == 0-31 + 127
48174 -                        * 
48175 +                        *
48176                          */
48177                         switch(*cur) {
48178                         case ':':
48179                                 is_key = 0;
48180 -                               
48181 +
48182                                 value = cur + 1;
48183 -                               
48184 +
48185                                 if (is_ws_after_key == 0) {
48186                                         key_len = i - first;
48187                                 }
48188                                 is_ws_after_key = 0;
48189 -                                       
48190 +
48191                                 break;
48192                         case '(':
48193                         case ')':
48194 @@ -584,8 +586,8 @@
48195                                 con->http_status = 400;
48196                                 con->keep_alive = 0;
48197                                 con->response.keep_alive = 0;
48198 -                               
48199 -                               log_error_write(srv, __FILE__, __LINE__, "sbsds", 
48200 +
48201 +                               log_error_write(srv, __FILE__, __LINE__, "sbsds",
48202                                                 "invalid character in key", con->request.request, cur, *cur, "-> 400");
48203                                 return 0;
48204                         case ' ':
48205 @@ -594,13 +596,13 @@
48206                                         is_key = 0;
48207                                         in_folding = 1;
48208                                         value = cur;
48209 -                                       
48210 +
48211                                         break;
48212                                 }
48213 -                               
48214 -                               
48215 +
48216 +
48217                                 key_len = i - first;
48218 -                               
48219 +
48220                                 /* skip every thing up to the : */
48221                                 for (j = 1; !got_colon; j++) {
48222                                         switch(con->parse_request->ptr[j + i]) {
48223 @@ -610,40 +612,40 @@
48224                                                 continue;
48225                                         case ':':
48226                                                 /* ok, done */
48227 -                                               
48228 +
48229                                                 i += j - 1;
48230                                                 got_colon = 1;
48231 -                                               
48232 +
48233                                                 break;
48234                                         default:
48235                                                 /* error */
48236 -                                               
48237 +
48238                                                 if (srv->srvconf.log_request_header_on_error) {
48239                                                         log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
48240                                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
48241                                                                 "request-header:\n",
48242                                                                 con->request.request);
48243                                                 }
48244 -                                       
48245 +
48246                                                 con->http_status = 400;
48247                                                 con->response.keep_alive = 0;
48248                                                 con->keep_alive = 0;
48249 -                                               
48250 +
48251                                                 return 0;
48252                                         }
48253                                 }
48254 -                               
48255 +
48256                                 break;
48257                         case '\r':
48258                                 if (con->parse_request->ptr[i+1] == '\n' && i == first) {
48259                                         /* End of Header */
48260                                         con->parse_request->ptr[i] = '\0';
48261                                         con->parse_request->ptr[i+1] = '\0';
48262 -                                       
48263 +
48264                                         i++;
48265 -                                       
48266 +
48267                                         done = 1;
48268 -                                       
48269 +
48270                                         break;
48271                                 } else {
48272                                         if (srv->srvconf.log_request_header_on_error) {
48273 @@ -652,7 +654,7 @@
48274                                                         "request-header:\n",
48275                                                         con->request.request);
48276                                         }
48277 -                                       
48278 +
48279                                         con->http_status = 400;
48280                                         con->keep_alive = 0;
48281                                         con->response.keep_alive = 0;
48282 @@ -693,16 +695,16 @@
48283                                 con->http_status = 400;
48284                                 con->keep_alive = 0;
48285                                 con->response.keep_alive = 0;
48286 -                               
48287 +
48288                                 if (srv->srvconf.log_request_header_on_error) {
48289 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsds", 
48290 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsds",
48291                                                 "CTL character in key", con->request.request, cur, *cur, "-> 400");
48292  
48293                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
48294                                                 "request-header:\n",
48295                                                 con->request.request);
48296                                 }
48297 -                               
48298 +
48299                                 return 0;
48300                         default:
48301                                 /* ok */
48302 @@ -710,25 +712,25 @@
48303                         }
48304                 } else {
48305                         switch(*cur) {
48306 -                       case '\r': 
48307 +                       case '\r':
48308                                 if (con->parse_request->ptr[i+1] == '\n') {
48309                                         /* End of Headerline */
48310                                         con->parse_request->ptr[i] = '\0';
48311                                         con->parse_request->ptr[i+1] = '\0';
48312 -                                       
48313 +
48314                                         if (in_folding) {
48315                                                 if (!ds) {
48316                                                         /* 400 */
48317 -                                       
48318 +
48319                                                         if (srv->srvconf.log_request_header_on_error) {
48320                                                                 log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
48321 -                                                       
48322 +
48323                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48324                                                                         "request-header:\n",
48325                                                                         con->request.request);
48326                                                         }
48327  
48328 -                                       
48329 +
48330                                                         con->http_status = 400;
48331                                                         con->keep_alive = 0;
48332                                                         con->response.keep_alive = 0;
48333 @@ -738,9 +740,9 @@
48334                                         } else {
48335                                                 int s_len;
48336                                                 key = con->parse_request->ptr + first;
48337 -                                       
48338 +
48339                                                 s_len = cur - value;
48340 -                                               
48341 +
48342                                                 if (s_len > 0) {
48343                                                         int cmp = 0;
48344                                                         if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
48345 @@ -748,86 +750,87 @@
48346                                                         }
48347                                                         buffer_copy_string_len(ds->key, key, key_len);
48348                                                         buffer_copy_string_len(ds->value, value, s_len);
48349 -                                                       
48350 -                                                       /* retreive values 
48351 -                                                        * 
48352 -                                                        * 
48353 +
48354 +                                                       /* retreive values
48355 +                                                        *
48356 +                                                        *
48357                                                          * the list of options is sorted to simplify the search
48358                                                          */
48359 -                                                       
48360 +
48361                                                         if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
48362                                                                 array *vals;
48363                                                                 size_t vi;
48364 -                                                               
48365 +
48366                                                                 /* split on , */
48367 -                                                               
48368 +
48369                                                                 vals = srv->split_vals;
48370  
48371                                                                 array_reset(vals);
48372 -                                                               
48373 +
48374                                                                 http_request_split_value(vals, ds->value);
48375 -                                                               
48376 +
48377                                                                 for (vi = 0; vi < vals->used; vi++) {
48378                                                                         data_string *dsv = (data_string *)vals->data[vi];
48379 -                                                                       
48380 +
48381                                                                         if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
48382                                                                                 keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
48383 -                                                                               
48384 +
48385                                                                                 break;
48386                                                                         } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
48387                                                                                 keep_alive_set = HTTP_CONNECTION_CLOSE;
48388 -                                                                               
48389 +
48390                                                                                 break;
48391                                                                         }
48392                                                                 }
48393 -                                                               
48394 +
48395                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
48396                                                                 char *err;
48397                                                                 unsigned long int r;
48398                                                                 size_t j;
48399 -                                                               
48400 +
48401                                                                 if (con_length_set) {
48402                                                                         con->http_status = 400;
48403                                                                         con->keep_alive = 0;
48404 -                                                                       
48405 +
48406                                                                         if (srv->srvconf.log_request_header_on_error) {
48407 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48408 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48409                                                                                                 "duplicate Content-Length-header -> 400");
48410                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48411                                                                                                 "request-header:\n",
48412                                                                                                 con->request.request);
48413                                                                         }
48414 +                                                                       ds->free((data_unset *) ds);
48415                                                                         return 0;
48416                                                                 }
48417 -                                                               
48418 +
48419                                                                 if (ds->value->used == 0) SEGFAULT();
48420 -                                                               
48421 +
48422                                                                 for (j = 0; j < ds->value->used - 1; j++) {
48423                                                                         char c = ds->value->ptr[j];
48424                                                                         if (!isdigit((unsigned char)c)) {
48425 -                                                                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
48426 +                                                                               log_error_write(srv, __FILE__, __LINE__, "sbs",
48427                                                                                                 "content-length broken:", ds->value, "-> 400");
48428 -                                                                               
48429 +
48430                                                                                 con->http_status = 400;
48431                                                                                 con->keep_alive = 0;
48432 -                                                                               
48433 +
48434                                                                                 array_insert_unique(con->request.headers, (data_unset *)ds);
48435                                                                                 return 0;
48436                                                                         }
48437                                                                 }
48438 -                                                               
48439 +
48440                                                                 r = strtoul(ds->value->ptr, &err, 10);
48441 -                                                               
48442 +
48443                                                                 if (*err == '\0') {
48444                                                                         con_length_set = 1;
48445                                                                         con->request.content_length = r;
48446                                                                 } else {
48447 -                                                                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
48448 +                                                                       log_error_write(srv, __FILE__, __LINE__, "sbs",
48449                                                                                         "content-length broken:", ds->value, "-> 400");
48450 -                                                                       
48451 +
48452                                                                         con->http_status = 400;
48453                                                                         con->keep_alive = 0;
48454 -                                                                       
48455 +
48456                                                                         array_insert_unique(con->request.headers, (data_unset *)ds);
48457                                                                         return 0;
48458                                                                 }
48459 @@ -838,23 +841,24 @@
48460                                                                 } else {
48461                                                                         con->http_status = 400;
48462                                                                         con->keep_alive = 0;
48463 -                                                                       
48464 +
48465                                                                         if (srv->srvconf.log_request_header_on_error) {
48466 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48467 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48468                                                                                                 "duplicate Content-Type-header -> 400");
48469                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48470                                                                                                 "request-header:\n",
48471                                                                                                 con->request.request);
48472                                                                         }
48473 +                                                                       ds->free((data_unset *) ds);
48474                                                                         return 0;
48475                                                                 }
48476                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
48477 -                                                               /* HTTP 2616 8.2.3 
48478 +                                                               /* HTTP 2616 8.2.3
48479                                                                  * Expect: 100-continue
48480 -                                                                * 
48481 +                                                                *
48482                                                                  *   -> (10.1.1)  100 (read content, process request, send final status-code)
48483                                                                  *   -> (10.4.18) 417 (close)
48484 -                                                                * 
48485 +                                                                *
48486                                                                  * (not handled at all yet, we always send 417 here)
48487                                                                  *
48488                                                                  * What has to be added ?
48489 @@ -863,10 +867,10 @@
48490                                                                  *    header
48491                                                                  *
48492                                                                  */
48493 -                                                               
48494 +
48495                                                                 con->http_status = 417;
48496                                                                 con->keep_alive = 0;
48497 -                                                               
48498 +
48499                                                                 array_insert_unique(con->request.headers, (data_unset *)ds);
48500                                                                 return 0;
48501                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
48502 @@ -875,14 +879,15 @@
48503                                                                 } else {
48504                                                                         con->http_status = 400;
48505                                                                         con->keep_alive = 0;
48506 -                                                                       
48507 +
48508                                                                         if (srv->srvconf.log_request_header_on_error) {
48509 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48510 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48511                                                                                                 "duplicate Host-header -> 400");
48512                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48513                                                                                                 "request-header:\n",
48514                                                                                                 con->request.request);
48515                                                                         }
48516 +                                                                       ds->free((data_unset *) ds);
48517                                                                         return 0;
48518                                                                 }
48519                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
48520 @@ -897,14 +902,15 @@
48521                                                                 } else {
48522                                                                         con->http_status = 400;
48523                                                                         con->keep_alive = 0;
48524 -                                                                       
48525 +
48526                                                                         if (srv->srvconf.log_request_header_on_error) {
48527 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48528 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48529                                                                                                 "duplicate If-Modified-Since header -> 400");
48530                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48531                                                                                                 "request-header:\n",
48532                                                                                                 con->request.request);
48533                                                                         }
48534 +                                                                       ds->free((data_unset *) ds);
48535                                                                         return 0;
48536                                                                 }
48537                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
48538 @@ -914,47 +920,49 @@
48539                                                                 } else {
48540                                                                         con->http_status = 400;
48541                                                                         con->keep_alive = 0;
48542 -                                                                       
48543 +
48544                                                                         if (srv->srvconf.log_request_header_on_error) {
48545 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48546 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48547                                                                                                 "duplicate If-None-Match-header -> 400");
48548                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48549                                                                                                 "request-header:\n",
48550                                                                                                 con->request.request);
48551                                                                         }
48552 +                                                                       ds->free((data_unset *) ds);
48553                                                                         return 0;
48554                                                                 }
48555                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
48556                                                                 if (!con->request.http_range) {
48557                                                                         /* bytes=.*-.* */
48558 -                                                               
48559 +
48560                                                                         if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) &&
48561                                                                             NULL != strchr(ds->value->ptr+6, '-')) {
48562 -                                                                               
48563 +
48564                                                                                 /* if dup, only the first one will survive */
48565                                                                                 con->request.http_range = ds->value->ptr + 6;
48566                                                                         }
48567                                                                 } else {
48568                                                                         con->http_status = 400;
48569                                                                         con->keep_alive = 0;
48570 -                                                                       
48571 +
48572                                                                         if (srv->srvconf.log_request_header_on_error) {
48573 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48574 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48575                                                                                                 "duplicate Range-header -> 400");
48576                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48577                                                                                                 "request-header:\n",
48578                                                                                                 con->request.request);
48579                                                                         }
48580 +                                                                       ds->free((data_unset *) ds);
48581                                                                         return 0;
48582                                                                 }
48583                                                         }
48584 -                                                       
48585 +
48586                                                         array_insert_unique(con->request.headers, (data_unset *)ds);
48587                                                 } else {
48588                                                         /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
48589                                                 }
48590                                         }
48591 -                                       
48592 +
48593                                         i++;
48594                                         first = i+1;
48595                                         is_key = 1;
48596 @@ -963,10 +971,10 @@
48597                                         in_folding = 0;
48598                                 } else {
48599                                         if (srv->srvconf.log_request_header_on_error) {
48600 -                                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
48601 +                                               log_error_write(srv, __FILE__, __LINE__, "sbs",
48602                                                                 "CR without LF", con->request.request, "-> 400");
48603                                         }
48604 -                                       
48605 +
48606                                         con->http_status = 400;
48607                                         con->keep_alive = 0;
48608                                         con->response.keep_alive = 0;
48609 @@ -982,28 +990,28 @@
48610                         }
48611                 }
48612         }
48613 -       
48614 +
48615         con->header_len = i;
48616 -       
48617 +
48618         /* do some post-processing */
48619  
48620         if (con->request.http_version == HTTP_VERSION_1_1) {
48621                 if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
48622                         /* no Connection-Header sent */
48623 -                       
48624 +
48625                         /* HTTP/1.1 -> keep-alive default TRUE */
48626                         con->keep_alive = 1;
48627                 } else {
48628                         con->keep_alive = 0;
48629                 }
48630 -               
48631 +
48632                 /* RFC 2616, 14.23 */
48633                 if (con->request.http_host == NULL ||
48634                     buffer_is_empty(con->request.http_host)) {
48635                         con->http_status = 400;
48636                         con->response.keep_alive = 0;
48637                         con->keep_alive = 0;
48638 -                       
48639 +
48640                         if (srv->srvconf.log_request_header_on_error) {
48641                                 log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
48642                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48643 @@ -1015,18 +1023,18 @@
48644         } else {
48645                 if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
48646                         /* no Connection-Header sent */
48647 -                       
48648 +
48649                         /* HTTP/1.0 -> keep-alive default FALSE  */
48650                         con->keep_alive = 1;
48651                 } else {
48652                         con->keep_alive = 0;
48653                 }
48654         }
48655 -       
48656 +
48657         /* check hostname field if it is set */
48658         if (NULL != con->request.http_host &&
48659             0 != request_check_hostname(srv, con, con->request.http_host)) {
48660 -               
48661 +
48662                 if (srv->srvconf.log_request_header_on_error) {
48663                         log_error_write(srv, __FILE__, __LINE__, "s",
48664                                         "Invalid Hostname -> 400");
48665 @@ -1038,7 +1046,7 @@
48666                 con->http_status = 400;
48667                 con->response.keep_alive = 0;
48668                 con->keep_alive = 0;
48669 -               
48670 +
48671                 return 0;
48672         }
48673  
48674 @@ -1048,7 +1056,7 @@
48675                 /* content-length is forbidden for those */
48676                 if (con_length_set && con->request.content_length != 0) {
48677                         /* content-length is missing */
48678 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
48679 +                       log_error_write(srv, __FILE__, __LINE__, "s",
48680                                         "GET/HEAD with content-length -> 400");
48681  
48682                         con->keep_alive = 0;
48683 @@ -1060,7 +1068,7 @@
48684                 /* content-length is required for them */
48685                 if (!con_length_set) {
48686                         /* content-length is missing */
48687 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
48688 +                       log_error_write(srv, __FILE__, __LINE__, "s",
48689                                         "POST-request, but content-length missing -> 411");
48690  
48691                         con->keep_alive = 0;
48692 @@ -1073,16 +1081,16 @@
48693                 /* the may have a content-length */
48694                 break;
48695         }
48696 -                       
48697 -       
48698 +
48699 +
48700         /* check if we have read post data */
48701         if (con_length_set) {
48702                 /* don't handle more the SSIZE_MAX bytes in content-length */
48703                 if (con->request.content_length > SSIZE_MAX) {
48704 -                       con->http_status = 413; 
48705 +                       con->http_status = 413;
48706                         con->keep_alive = 0;
48707  
48708 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
48709 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
48710                                         "request-size too long:", con->request.content_length, "-> 413");
48711                         return 0;
48712                 }
48713 @@ -1090,25 +1098,25 @@
48714                 /* divide by 1024 as srvconf.max_request_size is in kBytes */
48715                 if (srv->srvconf.max_request_size != 0 &&
48716                     (con->request.content_length >> 10) > srv->srvconf.max_request_size) {
48717 -                       /* the request body itself is larger then 
48718 +                       /* the request body itself is larger then
48719                          * our our max_request_size
48720                          */
48721 -               
48722 +
48723                         con->http_status = 413;
48724                         con->keep_alive = 0;
48725 -               
48726 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
48727 +
48728 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
48729                                         "request-size too long:", con->request.content_length, "-> 413");
48730                         return 0;
48731                 }
48732 -               
48733 -               
48734 +
48735 +
48736                 /* we have content */
48737                 if (con->request.content_length != 0) {
48738                         return 1;
48739                 }
48740         }
48741 -       
48742 +
48743         return 0;
48744  }
48745  
48746 @@ -1116,9 +1124,9 @@
48747         UNUSED(srv);
48748  
48749         if (con->request.request->used < 5) return 0;
48750 -       
48751 +
48752         if (0 == memcmp(con->request.request->ptr + con->request.request->used - 5, "\r\n\r\n", 4)) return 1;
48753         if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1;
48754 -       
48755 +
48756         return 0;
48757  }
48758 --- ../lighttpd-1.4.11/src/response.c   2006-03-04 16:41:39.000000000 +0200
48759 +++ lighttpd-1.4.12/src/response.c      2006-07-16 00:26:04.000000000 +0300
48760 @@ -7,7 +7,6 @@
48761  #include <stdlib.h>
48762  #include <string.h>
48763  #include <time.h>
48764 -#include <unistd.h>
48765  #include <ctype.h>
48766  #include <assert.h>
48767  
48768 @@ -24,15 +23,17 @@
48769  #include "plugin.h"
48770  
48771  #include "sys-socket.h"
48772 +#include "sys-files.h"
48773 +#include "sys-strings.h"
48774  
48775  int http_response_write_header(server *srv, connection *con) {
48776         buffer *b;
48777         size_t i;
48778         int have_date = 0;
48779         int have_server = 0;
48780 -       
48781 +
48782         b = chunkqueue_get_prepend_buffer(con->write_queue);
48783 -       
48784 +
48785         if (con->request.http_version == HTTP_VERSION_1_1) {
48786                 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
48787         } else {
48788 @@ -41,25 +42,26 @@
48789         buffer_append_long(b, con->http_status);
48790         BUFFER_APPEND_STRING_CONST(b, " ");
48791         buffer_append_string(b, get_http_status_name(con->http_status));
48792 -       
48793 +
48794         if (con->request.http_version != HTTP_VERSION_1_1 || con->keep_alive == 0) {
48795                 BUFFER_APPEND_STRING_CONST(b, "\r\nConnection: ");
48796                 buffer_append_string(b, con->keep_alive ? "keep-alive" : "close");
48797         }
48798 -       
48799 +
48800         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
48801                 BUFFER_APPEND_STRING_CONST(b, "\r\nTransfer-Encoding: chunked");
48802         }
48803 -       
48804 -       
48805 +
48806 +
48807         /* add all headers */
48808         for (i = 0; i < con->response.headers->used; i++) {
48809                 data_string *ds;
48810 -               
48811 +
48812                 ds = (data_string *)con->response.headers->data[i];
48813 -               
48814 +
48815                 if (ds->value->used && ds->key->used &&
48816 -                   0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1)) {
48817 +                   0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1) &&
48818 +                   0 != strcasecmp(ds->key->ptr, "X-Sendfile")) {
48819                         if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Date"))) have_date = 1;
48820                         if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Server"))) have_server = 1;
48821  
48822 @@ -68,28 +70,28 @@
48823                         BUFFER_APPEND_STRING_CONST(b, ": ");
48824                         buffer_append_string_buffer(b, ds->value);
48825  #if 0
48826 -                       log_error_write(srv, __FILE__, __LINE__, "bb", 
48827 +                       log_error_write(srv, __FILE__, __LINE__, "bb",
48828                                         ds->key, ds->value);
48829  #endif
48830                 }
48831         }
48832 -       
48833 +
48834         if (!have_date) {
48835                 /* HTTP/1.1 requires a Date: header */
48836                 BUFFER_APPEND_STRING_CONST(b, "\r\nDate: ");
48837 -       
48838 +
48839                 /* cache the generated timestamp */
48840                 if (srv->cur_ts != srv->last_generated_date_ts) {
48841                         buffer_prepare_copy(srv->ts_date_str, 255);
48842 -               
48843 -                       strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1, 
48844 +
48845 +                       strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
48846                                  "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts)));
48847 -                        
48848 +
48849                         srv->ts_date_str->used = strlen(srv->ts_date_str->ptr) + 1;
48850 -               
48851 +
48852                         srv->last_generated_date_ts = srv->cur_ts;
48853                 }
48854 -       
48855 +
48856                 buffer_append_string_buffer(b, srv->ts_date_str);
48857         }
48858  
48859 @@ -101,16 +103,16 @@
48860                         buffer_append_string_buffer(b, con->conf.server_tag);
48861                 }
48862         }
48863 -       
48864 +
48865         BUFFER_APPEND_STRING_CONST(b, "\r\n\r\n");
48866 -       
48867 -       
48868 +
48869 +
48870         con->bytes_header = b->used - 1;
48871 -       
48872 +
48873         if (con->conf.log_response_header) {
48874                 log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b);
48875         }
48876 -       
48877 +
48878         return 0;
48879  }
48880  
48881 @@ -118,71 +120,71 @@
48882  
48883  handler_t http_response_prepare(server *srv, connection *con) {
48884         handler_t r;
48885 -       
48886 -       /* looks like someone has already done a decision */
48887 -       if (con->mode == DIRECT && 
48888 +
48889 +       /* looks like someone has already made a decision */
48890 +       if (con->mode == DIRECT &&
48891             (con->http_status != 0 && con->http_status != 200)) {
48892                 /* remove a packets in the queue */
48893                 if (con->file_finished == 0) {
48894                         chunkqueue_reset(con->write_queue);
48895                 }
48896 -               
48897 +
48898                 return HANDLER_FINISHED;
48899         }
48900 -       
48901 +
48902         /* no decision yet, build conf->filename */
48903         if (con->mode == DIRECT && con->physical.path->used == 0) {
48904                 char *qstr;
48905  
48906 -               /* we only come here when we have the parse the full request again
48907 -                * 
48908 -                * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a 
48909 +               /* we only come here when we have to parse the full request again
48910 +                *
48911 +                * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
48912                  * problem here as mod_setenv might get called multiple times
48913                  *
48914                  * fastcgi-auth might lead to a COMEBACK too
48915                  * fastcgi again dead server too
48916                  *
48917                  * mod_compress might add headers twice too
48918 -                * 
48919 +                *
48920                  *  */
48921 -               
48922 +
48923                 if (con->conf.log_condition_handling) {
48924                         log_error_write(srv, __FILE__, __LINE__,  "s",  "run condition");
48925                 }
48926                 config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */
48927 -               
48928 +
48929                 /**
48930                  * prepare strings
48931 -                * 
48932 -                * - uri.path_raw 
48933 +                *
48934 +                * - uri.path_raw
48935                  * - uri.path (secure)
48936                  * - uri.query
48937 -                * 
48938 +                *
48939                  */
48940 -               
48941 -               /** 
48942 +
48943 +               /**
48944                  * Name according to RFC 2396
48945 -                * 
48946 +                *
48947                  * - scheme
48948                  * - authority
48949                  * - path
48950                  * - query
48951 -                * 
48952 +                *
48953                  * (scheme)://(authority)(path)?(query)
48954 -                * 
48955 -                * 
48956 +                *
48957 +                *
48958                  */
48959 -       
48960 +
48961                 buffer_copy_string(con->uri.scheme, con->conf.is_ssl ? "https" : "http");
48962                 buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
48963                 buffer_to_lower(con->uri.authority);
48964 -               
48965 +
48966                 config_patch_connection(srv, con, COMP_HTTP_HOST);      /* Host:        */
48967                 config_patch_connection(srv, con, COMP_HTTP_REMOTEIP);  /* Client-IP */
48968                 config_patch_connection(srv, con, COMP_HTTP_REFERER);   /* Referer:     */
48969                 config_patch_connection(srv, con, COMP_HTTP_USERAGENT); /* User-Agent:  */
48970                 config_patch_connection(srv, con, COMP_HTTP_COOKIE);    /* Cookie:  */
48971 -               
48972 +
48973                 /** extract query string from request.uri */
48974                 if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) {
48975                         buffer_copy_string    (con->uri.query, qstr + 1);
48976 @@ -200,22 +202,22 @@
48977                         log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-path     : ", con->uri.path_raw);
48978                         log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-query    : ", con->uri.query);
48979                 }
48980 -               
48981 +
48982                 /* disable keep-alive if requested */
48983 -               
48984 +
48985                 if (con->request_count > con->conf.max_keep_alive_requests) {
48986                         con->keep_alive = 0;
48987                 }
48988 -               
48989 -               
48990 +
48991 +
48992                 /**
48993 -                *  
48994 -                * call plugins 
48995 -                * 
48996 +                *
48997 +                * call plugins
48998 +                *
48999                  * - based on the raw URL
49000 -                * 
49001 +                *
49002                  */
49003 -               
49004 +
49005                 switch(r = plugins_call_handle_uri_raw(srv, con)) {
49006                 case HANDLER_GO_ON:
49007                         break;
49008 @@ -229,14 +231,14 @@
49009                         break;
49010                 }
49011  
49012 -               /* build filename 
49013 +               /* build filename
49014                  *
49015                  * - decode url-encodings  (e.g. %20 -> ' ')
49016                  * - remove path-modifiers (e.g. /../)
49017                  */
49018 -               
49019 -               
49020 -               
49021 +
49022 +
49023 +
49024                 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
49025                     con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
49026                         /* OPTIONS * ... */
49027 @@ -253,15 +255,20 @@
49028                 }
49029  
49030                 /**
49031 -                *  
49032 -                * call plugins 
49033 -                * 
49034 +                *
49035 +                * call plugins
49036 +                *
49037                  * - based on the clean URL
49038 -                * 
49039 +                *
49040                  */
49041 -               
49042 +
49043                 config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */
49044 -               
49045 +
49046 +               /* do we have to downgrade to 1.0 ? */
49047 +               if (!con->conf.allow_http11) {
49048 +                       con->request.http_version = HTTP_VERSION_1_0;
49049 +               }
49050 +
49051                 switch(r = plugins_call_handle_uri_clean(srv, con)) {
49052                 case HANDLER_GO_ON:
49053                         break;
49054 @@ -274,11 +281,11 @@
49055                         log_error_write(srv, __FILE__, __LINE__, "");
49056                         break;
49057                 }
49058 -               
49059 +
49060                 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
49061                     con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
49062 -                       /* option requests are handled directly without checking of the path */
49063 -               
49064 +                       /* option requests are handled directly without checking the path */
49065 +
49066                         response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
49067  
49068                         con->http_status = 200;
49069 @@ -288,46 +295,47 @@
49070                 }
49071  
49072                 /***
49073 -                * 
49074 -                * border 
49075 -                * 
49076 +                *
49077 +                * border
49078 +                *
49079                  * logical filename (URI) becomes a physical filename here
49080 -                * 
49081 -                * 
49082 -                * 
49083 +                *
49084 +                *
49085 +                *
49086                  */
49087 -               
49088 -               
49089 -               
49090 -               
49091 +
49092 +
49093 +
49094 +
49095                 /* 1. stat()
49096                  * ... ISREG() -> ok, go on
49097                  * ... ISDIR() -> index-file -> redirect
49098 -                * 
49099 -                * 2. pathinfo() 
49100 +                *
49101 +                * 2. pathinfo()
49102                  * ... ISREG()
49103 -                * 
49104 +                *
49105                  * 3. -> 404
49106 -                * 
49107 +                *
49108                  */
49109 -               
49110 +
49111                 /*
49112                  * SEARCH DOCUMENT ROOT
49113                  */
49114 -               
49115 +
49116                 /* set a default */
49117 -               
49118 +
49119                 buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root);
49120                 buffer_copy_string_buffer(con->physical.rel_path, con->uri.path);
49121 -               
49122 -#if defined(__WIN32) || defined(__CYGWIN__)
49123 -               /* strip dots from the end and spaces
49124 +
49125 +               filename_unix2local(con->physical.rel_path);
49126 +#if defined(_WIN32) || defined(__CYGWIN__)
49127 +               /* strip dots and spaces from the end
49128                  *
49129                  * windows/dos handle those filenames as the same file
49130                  *
49131                  * foo == foo. == foo..... == "foo...   " == "foo..  ./"
49132                  *
49133 -                * This will affect in some cases PATHINFO
49134 +                * This will affect PATHINFO in some cases
49135                  *
49136                  * on native windows we could prepend the filename with \\?\ to circumvent
49137                  * this behaviour. I have no idea how to push this through cygwin
49138 @@ -377,36 +385,41 @@
49139                         log_error_write(srv, __FILE__, __LINE__, "");
49140                         break;
49141                 }
49142 -               
49143 -               /* MacOS X and Windows can't distiguish between upper and lower-case 
49144 -                * 
49145 -                * convert to lower-case
49146 +
49147 +               /* The default Mac OS X and Windows filesystems can't distiguish between
49148 +                * upper- and lowercase, so convert to lowercase
49149                  */
49150                 if (con->conf.force_lowercase_filenames) {
49151                         buffer_to_lower(con->physical.rel_path);
49152                 }
49153  
49154 -               /* the docroot plugins might set the servername, if they don't we take http-host */
49155 +               /* the docroot plugins might set the servername; if they don't we take http-host */
49156                 if (buffer_is_empty(con->server_name)) {
49157                         buffer_copy_string_buffer(con->server_name, con->uri.authority);
49158                 }
49159 -               
49160 -               /** 
49161 -                * create physical filename 
49162 +
49163 +               /**
49164 +                * create physical filename
49165                  * -> physical.path = docroot + rel_path
49166 -                * 
49167 +                *
49168                  */
49169 -               
49170 +
49171                 buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
49172 -               BUFFER_APPEND_SLASH(con->physical.path);
49173 +               PATHNAME_APPEND_SLASH(con->physical.path);
49174                 buffer_copy_string_buffer(con->physical.basedir, con->physical.path);
49175                 if (con->physical.rel_path->used &&
49176 -                   con->physical.rel_path->ptr[0] == '/') {
49177 +                   con->physical.rel_path->ptr[0] == DIR_SEPERATOR) {
49178                         buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2);
49179                 } else {
49180                         buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
49181                 }
49182  
49183 +        /* win32: directories can't have a trailing slash */
49184 +        if (con->physical.path->ptr[con->physical.path->used - 2] == DIR_SEPERATOR) {
49185 +            con->physical.path->ptr[con->physical.path->used - 2] = '\0';
49186 +            con->physical.path->used--;
49187 +        }
49188 +
49189                 if (con->conf.log_request_handling) {
49190                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after doc_root");
49191                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
49192 @@ -426,7 +439,7 @@
49193                         log_error_write(srv, __FILE__, __LINE__, "");
49194                         break;
49195                 }
49196 -               
49197 +
49198                 if (con->conf.log_request_handling) {
49199                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- logical -> physical");
49200                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
49201 @@ -434,38 +447,38 @@
49202                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
49203                 }
49204         }
49205 -       
49206 -       /* 
49207 -        * Noone catched away the file from normal path of execution yet (like mod_access)
49208 -        * 
49209 +
49210 +       /*
49211 +        * No one took the file away from the normal path of execution yet (like mod_access)
49212 +        *
49213          * Go on and check of the file exists at all
49214          */
49215 -       
49216 +
49217         if (con->mode == DIRECT) {
49218                 char *slash = NULL;
49219                 char *pathinfo = NULL;
49220                 int found = 0;
49221                 stat_cache_entry *sce = NULL;
49222 -               
49223 +
49224                 if (con->conf.log_request_handling) {
49225                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling physical path");
49226                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
49227                 }
49228 -               
49229 +
49230                 if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
49231                         /* file exists */
49232 -                       
49233 +
49234                         if (con->conf.log_request_handling) {
49235                                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- file found");
49236                                 log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
49237                         }
49238 -                       
49239 +
49240                         if (S_ISDIR(sce->st.st_mode)) {
49241 -                               if (con->physical.path->ptr[con->physical.path->used - 2] != '/') {
49242 +                               if (con->uri.path->ptr[con->uri.path->used - 2] != '/') {
49243                                         /* redirect to .../ */
49244 -                                       
49245 +
49246                                         http_response_redirect_to_directory(srv, con);
49247 -                                       
49248 +
49249                                         return HANDLER_FINISHED;
49250                                 }
49251                         } else if (!S_ISREG(sce->st.st_mode)) {
49252 @@ -477,12 +490,12 @@
49253                         switch (errno) {
49254                         case EACCES:
49255                                 con->http_status = 403;
49256 -       
49257 +
49258                                 if (con->conf.log_request_handling) {
49259                                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied");
49260                                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
49261                                 }
49262 -                       
49263 +
49264                                 buffer_reset(con->physical.path);
49265                                 return HANDLER_FINISHED;
49266                         case ENOENT:
49267 @@ -499,77 +512,77 @@
49268                                 /* PATH_INFO ! :) */
49269                                 break;
49270                         default:
49271 -                               /* we have no idea what happend. let's tell the user so. */
49272 +                               /* we have no idea what happened, so tell the user. */
49273                                 con->http_status = 500;
49274                                 buffer_reset(con->physical.path);
49275 -                               
49276 +
49277                                 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
49278                                                 "file not found ... or so: ", strerror(errno),
49279                                                 con->uri.path,
49280                                                 "->", con->physical.path);
49281 -                               
49282 +
49283                                 return HANDLER_FINISHED;
49284                         }
49285 -                       
49286 +
49287                         /* not found, perhaps PATHINFO */
49288 -                       
49289 +
49290                         buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
49291 -                       
49292 +
49293                         do {
49294                                 struct stat st;
49295 -                               
49296 +
49297                                 if (slash) {
49298                                         buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr);
49299                                 } else {
49300                                         buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
49301                                 }
49302 -                               
49303 +
49304                                 if (0 == stat(con->physical.path->ptr, &(st)) &&
49305                                     S_ISREG(st.st_mode)) {
49306                                         found = 1;
49307                                         break;
49308                                 }
49309 -                               
49310 +
49311                                 if (pathinfo != NULL) {
49312                                         *pathinfo = '\0';
49313                                 }
49314                                 slash = strrchr(srv->tmp_buf->ptr, '/');
49315 -                               
49316 +
49317                                 if (pathinfo != NULL) {
49318                                         /* restore '/' */
49319                                         *pathinfo = '/';
49320                                 }
49321 -                               
49322 +
49323                                 if (slash) pathinfo = slash;
49324                         } while ((found == 0) && (slash != NULL) && (slash - srv->tmp_buf->ptr > con->physical.basedir->used - 2));
49325 -                       
49326 +
49327                         if (found == 0) {
49328 -                               /* no it really doesn't exists */
49329 +                               /* no, it really doesn't exists */
49330                                 con->http_status = 404;
49331 -                               
49332 +
49333                                 if (con->conf.log_file_not_found) {
49334                                         log_error_write(srv, __FILE__, __LINE__, "sbsb",
49335                                                         "file not found:", con->uri.path,
49336                                                         "->", con->physical.path);
49337                                 }
49338 -                               
49339 +
49340                                 buffer_reset(con->physical.path);
49341 -                               
49342 +
49343                                 return HANDLER_FINISHED;
49344                         }
49345 -                       
49346 +
49347                         /* we have a PATHINFO */
49348                         if (pathinfo) {
49349                                 buffer_copy_string(con->request.pathinfo, pathinfo);
49350 -                               
49351 +
49352                                 /*
49353                                  * shorten uri.path
49354                                  */
49355 -                               
49356 +
49357                                 con->uri.path->used -= strlen(pathinfo);
49358                                 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
49359                         }
49360 -                       
49361 +
49362                         if (con->conf.log_request_handling) {
49363                                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after pathinfo check");
49364                                 log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
49365 @@ -577,12 +590,12 @@
49366                                 log_error_write(srv, __FILE__, __LINE__,  "sb", "Pathinfo     :", con->request.pathinfo);
49367                         }
49368                 }
49369 -               
49370 +
49371                 if (con->conf.log_request_handling) {
49372                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling subrequest");
49373                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
49374                 }
49375 -               
49376 +
49377                 /* call the handlers */
49378                 switch(r = plugins_call_handle_subrequest_start(srv, con)) {
49379                 case HANDLER_GO_ON:
49380 @@ -593,32 +606,32 @@
49381                         if (con->conf.log_request_handling) {
49382                                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- subrequest finished");
49383                         }
49384 -                       
49385 -                       /* something strange happend */
49386 +
49387 +                       /* something strange happened */
49388                         return r;
49389                 }
49390 -               
49391 -               /* if we are still here, no one wanted the file, status 403 is ok I think */
49392 -               
49393 +
49394 +               /* if we are still here, no one wanted the file; status 403 is ok I think */
49395 +
49396                 if (con->mode == DIRECT) {
49397                         con->http_status = 403;
49398 -                       
49399 +
49400                         return HANDLER_FINISHED;
49401                 }
49402 -               
49403 +
49404         }
49405 -       
49406 +
49407         switch(r = plugins_call_handle_subrequest(srv, con)) {
49408         case HANDLER_GO_ON:
49409 -               /* request was not handled, looks like we are done */
49410 +               /* request was not handled; looks like we are done */
49411                 return HANDLER_FINISHED;
49412         case HANDLER_FINISHED:
49413                 /* request is finished */
49414         default:
49415 -               /* something strange happend */
49416 +               /* something strange happened */
49417                 return r;
49418         }
49419 -       
49420 +
49421         /* can't happen */
49422         return HANDLER_COMEBACK;
49423  }
49424 --- ../lighttpd-1.4.11/src/server.c     2006-03-04 19:12:17.000000000 +0200
49425 +++ lighttpd-1.4.12/src/server.c        2006-07-19 20:02:55.000000000 +0300
49426 @@ -1,11 +1,9 @@
49427  #include <sys/types.h>
49428 -#include <sys/time.h>
49429  #include <sys/stat.h>
49430  
49431  #include <string.h>
49432  #include <errno.h>
49433  #include <fcntl.h>
49434 -#include <unistd.h>
49435  #include <stdlib.h>
49436  #include <time.h>
49437  #include <signal.h>
49438 @@ -29,9 +27,15 @@
49439  #include "plugin.h"
49440  #include "joblist.h"
49441  #include "network_backends.h"
49442 -
49443 +#include "status_counter.h"
49444 +#ifdef _WIN32
49445 +/* use local getopt implementation */
49446 +# undef HAVE_GETOPT_H
49447 +#endif
49448  #ifdef HAVE_GETOPT_H
49449  #include <getopt.h>
49450 +#else
49451 +#include "getopt.h"
49452  #endif
49453  
49454  #ifdef HAVE_VALGRIND_VALGRIND_H
49455 @@ -60,8 +64,17 @@
49456  /* #define USE_ALARM */
49457  #endif
49458  
49459 +#ifdef _WIN32
49460 +#undef HAVE_SIGNAL
49461 +#endif
49462 +
49463 +#include "sys-files.h"
49464 +#include "sys-process.h"
49465 +#include "sys-socket.h"
49466 +
49467  static volatile sig_atomic_t srv_shutdown = 0;
49468  static volatile sig_atomic_t graceful_shutdown = 0;
49469 +static volatile sig_atomic_t graceful_restart = 0;
49470  static volatile sig_atomic_t handle_sig_alarm = 1;
49471  static volatile sig_atomic_t handle_sig_hup = 0;
49472  
49473 @@ -72,9 +85,9 @@
49474  
49475         switch (sig) {
49476         case SIGTERM: srv_shutdown = 1; break;
49477 -       case SIGINT: 
49478 +       case SIGINT:
49479              if (graceful_shutdown) srv_shutdown = 1;
49480 -            else graceful_shutdown = 1; 
49481 +            else graceful_shutdown = 1;
49482  
49483              break;
49484         case SIGALRM: handle_sig_alarm = 1; break;
49485 @@ -86,9 +99,9 @@
49486  static void signal_handler(int sig) {
49487         switch (sig) {
49488         case SIGTERM: srv_shutdown = 1; break;
49489 -       case SIGINT: 
49490 +       case SIGINT:
49491              if (graceful_shutdown) srv_shutdown = 1;
49492 -            else graceful_shutdown = 1; 
49493 +            else graceful_shutdown = 1;
49494  
49495              break;
49496         case SIGALRM: handle_sig_alarm = 1; break;
49497 @@ -110,35 +123,35 @@
49498         signal(SIGTSTP, SIG_IGN);
49499  #endif
49500         if (0 != fork()) exit(0);
49501 -       
49502 +
49503         if (-1 == setsid()) exit(0);
49504  
49505         signal(SIGHUP, SIG_IGN);
49506  
49507         if (0 != fork()) exit(0);
49508 -       
49509 +
49510         if (0 != chdir("/")) exit(0);
49511  }
49512  #endif
49513  
49514  static server *server_init(void) {
49515         int i;
49516 -       
49517 +
49518         server *srv = calloc(1, sizeof(*srv));
49519         assert(srv);
49520 +    srv->max_fds = 1024;
49521  #define CLEAN(x) \
49522         srv->x = buffer_init();
49523 -       
49524 +
49525         CLEAN(response_header);
49526         CLEAN(parse_full_path);
49527         CLEAN(ts_debug_str);
49528         CLEAN(ts_date_str);
49529 -       CLEAN(errorlog_buf);
49530         CLEAN(response_range);
49531         CLEAN(tmp_buf);
49532         srv->empty_string = buffer_init_string("");
49533         CLEAN(cond_check_buf);
49534 -       
49535 +
49536         CLEAN(srvconf.errorlog_file);
49537         CLEAN(srvconf.groupname);
49538         CLEAN(srvconf.username);
49539 @@ -146,68 +159,62 @@
49540         CLEAN(srvconf.bindhost);
49541         CLEAN(srvconf.event_handler);
49542         CLEAN(srvconf.pid_file);
49543 -       
49544 +
49545         CLEAN(tmp_chunk_len);
49546  #undef CLEAN
49547 -       
49548 +
49549  #define CLEAN(x) \
49550         srv->x = array_init();
49551 -       
49552 +
49553         CLEAN(config_context);
49554         CLEAN(config_touched);
49555 -       CLEAN(status);
49556  #undef CLEAN
49557 -       
49558 +
49559         for (i = 0; i < FILE_CACHE_MAX; i++) {
49560                 srv->mtime_cache[i].str = buffer_init();
49561         }
49562 -       
49563 +
49564         srv->cur_ts = time(NULL);
49565         srv->startup_ts = srv->cur_ts;
49566 -       
49567 +
49568         srv->conns = calloc(1, sizeof(*srv->conns));
49569         assert(srv->conns);
49570 -       
49571 +
49572         srv->joblist = calloc(1, sizeof(*srv->joblist));
49573         assert(srv->joblist);
49574 -       
49575 +
49576         srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue));
49577         assert(srv->fdwaitqueue);
49578 -       
49579 +
49580         srv->srvconf.modules = array_init();
49581         srv->srvconf.modules_dir = buffer_init_string(LIBRARY_DIR);
49582         srv->srvconf.network_backend = buffer_init();
49583         srv->srvconf.upload_tempdirs = array_init();
49584 -       
49585 -       /* use syslog */
49586 -       srv->errorlog_fd = -1;
49587 -       srv->errorlog_mode = ERRORLOG_STDERR;
49588  
49589         srv->split_vals = array_init();
49590 -       
49591 +
49592         return srv;
49593  }
49594  
49595  static void server_free(server *srv) {
49596         size_t i;
49597 -       
49598 +
49599         for (i = 0; i < FILE_CACHE_MAX; i++) {
49600                 buffer_free(srv->mtime_cache[i].str);
49601         }
49602 -       
49603 +
49604  #define CLEAN(x) \
49605         buffer_free(srv->x);
49606 -       
49607 +
49608         CLEAN(response_header);
49609         CLEAN(parse_full_path);
49610         CLEAN(ts_debug_str);
49611         CLEAN(ts_date_str);
49612 -       CLEAN(errorlog_buf);
49613         CLEAN(response_range);
49614         CLEAN(tmp_buf);
49615         CLEAN(empty_string);
49616         CLEAN(cond_check_buf);
49617 -       
49618 +
49619         CLEAN(srvconf.errorlog_file);
49620         CLEAN(srvconf.groupname);
49621         CLEAN(srvconf.username);
49622 @@ -217,7 +224,7 @@
49623         CLEAN(srvconf.pid_file);
49624         CLEAN(srvconf.modules_dir);
49625         CLEAN(srvconf.network_backend);
49626 -       
49627 +
49628         CLEAN(tmp_chunk_len);
49629  #undef CLEAN
49630  
49631 @@ -225,15 +232,15 @@
49632         fdevent_unregister(srv->ev, srv->fd);
49633  #endif
49634         fdevent_free(srv->ev);
49635 -       
49636 +
49637         free(srv->conns);
49638 -       
49639 +
49640         if (srv->config_storage) {
49641                 for (i = 0; i < srv->config_context->used; i++) {
49642                         specific_config *s = srv->config_storage[i];
49643  
49644                         if (!s) continue;
49645 -                       
49646 +
49647                         buffer_free(s->document_root);
49648                         buffer_free(s->server_name);
49649                         buffer_free(s->server_tag);
49650 @@ -242,32 +249,31 @@
49651                         buffer_free(s->error_handler);
49652                         buffer_free(s->errorfile_prefix);
49653                         array_free(s->mimetypes);
49654 -                       
49655 +
49656                         free(s);
49657                 }
49658                 free(srv->config_storage);
49659                 srv->config_storage = NULL;
49660         }
49661 -       
49662 +
49663  #define CLEAN(x) \
49664         array_free(srv->x);
49665 -       
49666 +
49667         CLEAN(config_context);
49668         CLEAN(config_touched);
49669 -       CLEAN(status);
49670         CLEAN(srvconf.upload_tempdirs);
49671  #undef CLEAN
49672 -       
49673 +
49674         joblist_free(srv, srv->joblist);
49675         fdwaitqueue_free(srv, srv->fdwaitqueue);
49676 -       
49677 +
49678         if (srv->stat_cache) {
49679                 stat_cache_free(srv->stat_cache);
49680         }
49681  
49682         array_free(srv->srvconf.modules);
49683         array_free(srv->split_vals);
49684 -       
49685 +
49686         free(srv);
49687  }
49688  
49689 @@ -281,14 +287,12 @@
49690  " - a light and fast webserver\n" \
49691  "Build-Date: " __DATE__ " " __TIME__ "\n";
49692  ;
49693 -#undef TEXT_SSL        
49694 +#undef TEXT_SSL
49695         write(STDOUT_FILENO, b, strlen(b));
49696  }
49697  
49698  static void show_features (void) {
49699 -  show_version();
49700 -  printf("\nEvent Handlers:\n\n%s",
49701 -
49702 +  const char *s = ""
49703  #ifdef USE_SELECT
49704        "\t+ select (generic)\n"
49705  #else
49706 @@ -355,11 +359,6 @@
49707  #else
49708        "\t- crypt support\n"
49709  #endif
49710 -#ifdef USE_PAM
49711 -      "\t+ PAM support\n"
49712 -#else
49713 -      "\t- PAM support\n"
49714 -#endif
49715  #ifdef USE_OPENSSL
49716        "\t+ SSL Support\n"
49717  #else
49718 @@ -371,9 +370,9 @@
49719        "\t- PCRE support\n"
49720  #endif
49721  #ifdef HAVE_MYSQL
49722 -      "\t+ mySQL support\n"
49723 +      "\t+ MySQL support\n"
49724  #else
49725 -      "\t- mySQL support\n"
49726 +      "\t- MySQL support\n"
49727  #endif
49728  #if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
49729        "\t+ LDAP support\n"
49730 @@ -410,8 +409,11 @@
49731  #else
49732        "\t- GDBM support\n"
49733  #endif
49734 -      "\n"
49735 -      );
49736 +      "\n";
49737 +
49738 +  show_version();
49739 +
49740 +  printf("\nEvent Handlers:\n\n%s", s);
49741  }
49742  
49743  static void show_help (void) {
49744 @@ -433,197 +435,565 @@
49745  " -h         show this help\n" \
49746  "\n"
49747  ;
49748 -#undef TEXT_SSL        
49749 +#undef TEXT_SSL
49750  #undef TEXT_IPV6
49751         write(STDOUT_FILENO, b, strlen(b));
49752  }
49753  
49754 -int main (int argc, char **argv) {
49755 -       server *srv = NULL;
49756 -       int print_config = 0;
49757 -       int test_config = 0;
49758 -       int i_am_root;
49759 -       int o;
49760 -       int num_childs = 0;
49761 -       int pid_fd = -1, fd;
49762 -       size_t i;
49763 -#ifdef HAVE_SIGACTION
49764 -       struct sigaction act;
49765 -#endif
49766 -#ifdef HAVE_GETRLIMIT
49767 -       struct rlimit rlim;
49768 -#endif
49769 -       
49770 -#ifdef USE_ALARM
49771 -       struct itimerval interval;
49772 -       
49773 -       interval.it_interval.tv_sec = 1;
49774 -       interval.it_interval.tv_usec = 0;
49775 -       interval.it_value.tv_sec = 1;
49776 -       interval.it_value.tv_usec = 0;
49777 -#endif
49778 -       
49779 -       
49780 -       /* for nice %b handling in strfime() */
49781 -       setlocale(LC_TIME, "C");
49782 -       
49783 -       if (NULL == (srv = server_init())) {
49784 -               fprintf(stderr, "did this really happen?\n");
49785 -               return -1;
49786 -       }
49787 -       
49788 -       /* init structs done */
49789 -       
49790 -       srv->srvconf.port = 0;
49791 -#ifdef HAVE_GETUID
49792 -       i_am_root = (getuid() == 0);
49793 -#else
49794 -       i_am_root = 0;
49795 -#endif
49796 -       srv->srvconf.dont_daemonize = 0;
49797 -       
49798 -       while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
49799 -               switch(o) {
49800 -               case 'f': 
49801 -                       if (config_read(srv, optarg)) { 
49802 -                               server_free(srv);
49803 -                               return -1;
49804 -                       }
49805 -                       break;
49806 -               case 'm':
49807 -                       buffer_copy_string(srv->srvconf.modules_dir, optarg);
49808 -                       break;
49809 -               case 'p': print_config = 1; break;
49810 -               case 't': test_config = 1; break;
49811 -               case 'D': srv->srvconf.dont_daemonize = 1; break;
49812 -               case 'v': show_version(); return 0;
49813 -               case 'V': show_features(); return 0;          
49814 -               case 'h': show_help(); return 0;
49815 -               default: 
49816 -                       show_help();
49817 -                       server_free(srv);
49818 -                       return -1;
49819 -               }
49820 -       }
49821 -       
49822 -       if (!srv->config_storage) {
49823 -               log_error_write(srv, __FILE__, __LINE__, "s",
49824 -                               "No configuration available. Try using -f option.");
49825 -               
49826 -               server_free(srv);
49827 -               return -1;
49828 -       }
49829 -       
49830 -       if (print_config) {
49831 -               data_unset *dc = srv->config_context->data[0];
49832 -               if (dc) {
49833 -                       dc->print(dc, 0);
49834 -                       fprintf(stderr, "\n");
49835 -               } else {
49836 -                       /* shouldn't happend */
49837 -                       fprintf(stderr, "global config not found\n");
49838 -               }
49839 -       }
49840 +int lighty_mainloop(server *srv) {
49841 +       fdevent_revents *revents = fdevent_revents_init();
49842  
49843 -       if (test_config) {
49844 -               printf("Syntax OK\n");
49845 -       }
49846 +       /* main-loop */
49847 +       while (!srv_shutdown) {
49848 +               int n;
49849 +               size_t ndx;
49850 +               time_t min_ts;
49851  
49852 -       if (test_config || print_config) {
49853 -               server_free(srv);
49854 -               return 0;
49855 -       }
49856 -       
49857 -       /* close stdin and stdout, as they are not needed */
49858 -       /* move stdin to /dev/null */
49859 -       if (-1 != (fd = open("/dev/null", O_RDONLY))) {
49860 -               close(STDIN_FILENO);
49861 -               dup2(fd, STDIN_FILENO);
49862 -               close(fd);
49863 -       }
49864 -       
49865 -       /* move stdout to /dev/null */
49866 -       if (-1 != (fd = open("/dev/null", O_WRONLY))) {
49867 -               close(STDOUT_FILENO);
49868 -               dup2(fd, STDOUT_FILENO);
49869 -               close(fd);
49870 -       }
49871 -       
49872 -       if (0 != config_set_defaults(srv)) {
49873 -               log_error_write(srv, __FILE__, __LINE__, "s", 
49874 -                               "setting default values failed");
49875 -               server_free(srv);
49876 -               return -1;
49877 -       }
49878 -       
49879 -       /* UID handling */
49880 -#ifdef HAVE_GETUID
49881 -       if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
49882 -               /* we are setuid-root */
49883 -               
49884 -               log_error_write(srv, __FILE__, __LINE__, "s", 
49885 -                               "Are you nuts ? Don't apply a SUID bit to this binary");
49886 -               
49887 -               server_free(srv);
49888 -               return -1;
49889 -       }
49890 -#endif
49891 -       
49892 -       /* check document-root */
49893 -       if (srv->config_storage[0]->document_root->used <= 1) {
49894 -               log_error_write(srv, __FILE__, __LINE__, "s", 
49895 -                               "document-root is not set\n");
49896 -               
49897 -               server_free(srv);
49898 -               
49899 -               return -1;
49900 -       }
49901 -       
49902 -       if (plugins_load(srv)) {
49903 -               log_error_write(srv, __FILE__, __LINE__, "s",
49904 -                               "loading plugins finally failed");
49905 -               
49906 -               plugins_free(srv);
49907 -               server_free(srv);
49908 -               
49909 -               return -1;
49910 -       }
49911 -       
49912 -       /* open pid file BEFORE chroot */
49913 -       if (srv->srvconf.pid_file->used) {
49914 -               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))) {
49915 -                       struct stat st;
49916 -                       if (errno != EEXIST) {
49917 -                               log_error_write(srv, __FILE__, __LINE__, "sbs",
49918 -                                       "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49919 -                               return -1;
49920 -                       }
49921 -                       
49922 -                       if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
49923 -                               log_error_write(srv, __FILE__, __LINE__, "sbs",
49924 -                                               "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49925 +               if (handle_sig_hup) {
49926 +                       handler_t r;
49927 +
49928 +                       /* reset notification */
49929 +                       handle_sig_hup = 0;
49930 +
49931 +#if 0
49932 +                               pid_t pid;
49933 +
49934 +                       /* send the old process into a graceful-shutdown and start a
49935 +                        * new process right away
49936 +                        *
49937 +                        * BUGS:
49938 +                        * - if webserver is running on port < 1024 (e.g. 80, 433)
49939 +                        *   we don't have the permissions to bind to that port anymore
49940 +                        *
49941 +                        *
49942 +                        *  */
49943 +                       if (0 == (pid = fork())) {
49944 +                               execve(argv[0], argv, envp);
49945 +
49946 +                               exit(-1);
49947 +                       } else if (pid == -1) {
49948 +
49949 +                       } else {
49950 +                               /* parent */
49951 +
49952 +                               graceful_shutdown = 1; /* shutdown without killing running connections */
49953 +                               graceful_restart = 1;  /* don't delete pid file */
49954                         }
49955 -                       
49956 -                       if (!S_ISREG(st.st_mode)) {
49957 -                               log_error_write(srv, __FILE__, __LINE__, "sb",
49958 -                                               "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
49959 -                               return -1;
49960 +#else
49961 +                       /* cycle logfiles */
49962 +
49963 +                       switch(r = plugins_call_handle_sighup(srv)) {
49964 +                       case HANDLER_GO_ON:
49965 +                               break;
49966 +                       default:
49967 +                               log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
49968 +                               break;
49969                         }
49970 -                       
49971 -                       if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
49972 -                               log_error_write(srv, __FILE__, __LINE__, "sbs",
49973 -                                               "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49974 +
49975 +                       if (-1 == log_error_cycle()) {
49976 +                               log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
49977 +
49978                                 return -1;
49979                         }
49980 +#endif
49981                 }
49982 -       }
49983  
49984 -       if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
49985 -               /* select limits itself
49986 +               if (handle_sig_alarm) {
49987 +                       /* a new second */
49988 +
49989 +#ifdef USE_ALARM
49990 +                       /* reset notification */
49991 +                       handle_sig_alarm = 0;
49992 +#endif
49993 +
49994 +                       /* get current time */
49995 +                       min_ts = time(NULL);
49996 +
49997 +                       if (min_ts != srv->cur_ts) {
49998 +                               int cs = 0;
49999 +                               connections *conns = srv->conns;
50000 +                               handler_t r;
50001 +
50002 +                               switch(r = plugins_call_handle_trigger(srv)) {
50003 +                               case HANDLER_GO_ON:
50004 +                                       break;
50005 +                               case HANDLER_ERROR:
50006 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
50007 +                                       break;
50008 +                               default:
50009 +                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
50010 +                                       break;
50011 +                               }
50012 +
50013 +                               /* trigger waitpid */
50014 +                               srv->cur_ts = min_ts;
50015 +
50016 +                               /* cleanup stat-cache */
50017 +                               stat_cache_trigger_cleanup(srv);
50018 +                               /**
50019 +                                * check all connections for timeouts
50020 +                                *
50021 +                                */
50022 +                               for (ndx = 0; ndx < conns->used; ndx++) {
50023 +                                       int changed = 0;
50024 +                                       connection *con;
50025 +                                       int t_diff;
50026 +
50027 +                                       con = conns->ptr[ndx];
50028 +
50029 +                                       if (con->state == CON_STATE_READ ||
50030 +                                           con->state == CON_STATE_READ_POST) {
50031 +                                               if (con->request_count == 1) {
50032 +                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
50033 +                                                               /* time - out */
50034 +#if 0
50035 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
50036 +                                                                               "connection closed - read-timeout:", con->fd);
50037 +#endif
50038 +                                                               connection_set_state(srv, con, CON_STATE_ERROR);
50039 +                                                               changed = 1;
50040 +                                                       }
50041 +                                               } else {
50042 +                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
50043 +                                                               /* time - out */
50044 +#if 0
50045 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
50046 +                                                                               "connection closed - read-timeout:", con->fd);
50047 +#endif
50048 +                                                               connection_set_state(srv, con, CON_STATE_ERROR);
50049 +                                                               changed = 1;
50050 +                                                       }
50051 +                                               }
50052 +                                       }
50053 +
50054 +                                       if ((con->state == CON_STATE_WRITE) &&
50055 +                                           (con->write_request_ts != 0)) {
50056 +#if 0
50057 +                                               if (srv->cur_ts - con->write_request_ts > 60) {
50058 +                                                       log_error_write(srv, __FILE__, __LINE__, "sdd",
50059 +                                                                       "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
50060 +                                               }
50061 +#endif
50062 +
50063 +                                               if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
50064 +                                                       /* time - out */
50065 +#if 1
50066 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsosds",
50067 +                                                                       "NOTE: a request for",
50068 +                                                                       con->request.uri,
50069 +                                                                       "timed out after writing",
50070 +                                                                       con->bytes_written,
50071 +                                                                       "bytes. We waited",
50072 +                                                                       (int)con->conf.max_write_idle,
50073 +                                                                       "seconds. If this a problem increase server.max-write-idle");
50074 +#endif
50075 +                                                       connection_set_state(srv, con, CON_STATE_ERROR);
50076 +                                                       changed = 1;
50077 +                                               }
50078 +                                       }
50079 +                                       /* we don't like div by zero */
50080 +                                       if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
50081 +
50082 +                                       if (con->traffic_limit_reached &&
50083 +                                           (con->conf.kbytes_per_second == 0 ||
50084 +                                            ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
50085 +                                               /* enable connection again */
50086 +                                               con->traffic_limit_reached = 0;
50087 +
50088 +                                               changed = 1;
50089 +                                       }
50090 +
50091 +                                       if (changed) {
50092 +                                               connection_state_machine(srv, con);
50093 +                                       }
50094 +                                       con->bytes_written_cur_second = 0;
50095 +                                       *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
50096 +
50097 +#if 0
50098 +                                       if (cs == 0) {
50099 +                                               fprintf(stderr, "connection-state: ");
50100 +                                               cs = 1;
50101 +                                       }
50102 +
50103 +                                       fprintf(stderr, "c[%d,%d]: %s ",
50104 +                                               con->fd,
50105 +                                               con->fcgi.fd,
50106 +                                               connection_get_state(con->state));
50107 +#endif
50108 +                               }
50109 +
50110 +                               if (cs == 1) fprintf(stderr, "\n");
50111 +                       }
50112 +               }
50113 +
50114 +               if (srv->sockets_disabled) {
50115 +                       /* our server sockets are disabled, why ? */
50116 +
50117 +                       if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
50118 +                           (srv->conns->used < srv->max_conns * 0.9) &&
50119 +                           (0 == graceful_shutdown)) {
50120 +                               size_t i;
50121 +
50122 +                               for (i = 0; i < srv->srv_sockets.used; i++) {
50123 +                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
50124 +                                       fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
50125 +                               }
50126 +
50127 +                               log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
50128 +
50129 +                               srv->sockets_disabled = 0;
50130 +                       }
50131 +               } else {
50132 +                       if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
50133 +                           (srv->conns->used > srv->max_conns) || /* out of connections */
50134 +                           (graceful_shutdown)) { /* graceful_shutdown */
50135 +                               size_t i;
50136 +
50137 +                               /* disable server-fds */
50138 +
50139 +                               for (i = 0; i < srv->srv_sockets.used; i++) {
50140 +                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
50141 +                                       fdevent_event_del(srv->ev, srv_socket->sock);
50142 +
50143 +                                       if (graceful_shutdown) {
50144 +                                               /* we don't want this socket anymore,
50145 +                                                *
50146 +                                                * closing it right away will make it possible for
50147 +                                                * the next lighttpd to take over (graceful restart)
50148 +                                                *  */
50149 +
50150 +                                               fdevent_unregister(srv->ev, srv_socket->sock);
50151 +                                               closesocket(srv_socket->sock->fd);
50152 +                                               srv_socket->sock->fd = -1;
50153 +
50154 +                                               /* network_close() will cleanup after us */
50155 +                                       }
50156 +                               }
50157 +
50158 +                               if (graceful_shutdown) {
50159 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
50160 +                               } else if (srv->conns->used > srv->max_conns) {
50161 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
50162 +                               } else {
50163 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
50164 +                               }
50165 +
50166 +                               srv->sockets_disabled = 1;
50167 +                       }
50168 +               }
50169 +
50170 +               if (graceful_shutdown && srv->conns->used == 0) {
50171 +                       /* we are in graceful shutdown phase and all connections are closed
50172 +                        * we are ready to terminate without harming anyone */
50173 +                       srv_shutdown = 1;
50174 +               }
50175 +
50176 +               /* we still have some fds to share */
50177 +               if (srv->want_fds) {
50178 +                       /* check the fdwaitqueue for waiting fds */
50179 +                       int free_fds = srv->max_fds - srv->cur_fds - 16;
50180 +                       connection *con;
50181 +
50182 +                       for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
50183 +                               connection_state_machine(srv, con);
50184 +
50185 +                               srv->want_fds--;
50186 +                       }
50187 +               }
50188 +
50189 +               if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
50190 +                       /* n is the number of events */
50191 +                       size_t i;
50192 +                       fdevent_get_revents(srv->ev, n, revents);
50193 +
50194 +                       /* handle client connections first
50195 +                        * 
50196 +                        * this is a bit of a hack, but we have to make sure than we handle 
50197 +                        * close-events before the connection is reused for a keep-alive 
50198 +                        * request
50199 +                        *
50200 +                        * this is mostly an issue for mod_proxy_core, but you never know
50201 +                        *
50202 +                        */
50203 +
50204 +                       for (i = 0; i < revents->used; i++) {
50205 +                               fdevent_revent *revent = revents->ptr[i];
50206 +                               handler_t r;
50207 +
50208 +                               /* skip server-fds */
50209 +                               if (revent->handler == network_server_handle_fdevent) continue;
50210 +
50211 +                               switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
50212 +                               case HANDLER_FINISHED:
50213 +                               case HANDLER_GO_ON:
50214 +                               case HANDLER_WAIT_FOR_EVENT:
50215 +                               case HANDLER_WAIT_FOR_FD:
50216 +                                       break;
50217 +                               case HANDLER_ERROR:
50218 +                                       /* should never happen */
50219 +                                       SEGFAULT();
50220 +                                       break;
50221 +                               default:
50222 +                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
50223 +                                       break;
50224 +                               }
50225 +                       } 
50226 +
50227 +                       for (i = 0; i < revents->used; i++) {
50228 +                               fdevent_revent *revent = revents->ptr[i];
50229 +                               handler_t r;
50230 +
50231 +                               /* server fds only */
50232 +                               if (revent->handler != network_server_handle_fdevent) continue;
50233 +
50234 +                               switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
50235 +                               case HANDLER_FINISHED:
50236 +                               case HANDLER_GO_ON:
50237 +                               case HANDLER_WAIT_FOR_EVENT:
50238 +                               case HANDLER_WAIT_FOR_FD:
50239 +                                       break;
50240 +                               case HANDLER_ERROR:
50241 +                                       /* should never happen */
50242 +                                       SEGFAULT();
50243 +                                       break;
50244 +                               default:
50245 +                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
50246 +                                       break;
50247 +                               }
50248 +                       } 
50249 +
50250 +               } else if (n < 0 && errno != EINTR) {
50251 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
50252 +                                       "fdevent_poll failed:",
50253 +                                       strerror(errno));
50254 +               }
50255 +
50256 +               for (ndx = 0; ndx < srv->joblist->used; ndx++) {
50257 +                       connection *con = srv->joblist->ptr[ndx];
50258 +                       handler_t r;
50259 +
50260 +                       connection_state_machine(srv, con);
50261 +
50262 +                       switch(r = plugins_call_handle_joblist(srv, con)) {
50263 +                       case HANDLER_FINISHED:
50264 +                       case HANDLER_GO_ON:
50265 +                               break;
50266 +                       default:
50267 +                               log_error_write(srv, __FILE__, __LINE__, "d", r);
50268 +                               break;
50269 +                       }
50270 +
50271 +                       con->in_joblist = 0;
50272 +               }
50273 +
50274 +               srv->joblist->used = 0;
50275 +       }
50276 +
50277 +       fdevent_revents_free(revents);
50278 +
50279 +       return 0;
50280 +}
50281 +
50282 +
50283 +int main (int argc, char **argv, char **envp) {
50284 +       server *srv = NULL;
50285 +       int print_config = 0;
50286 +       int test_config = 0;
50287 +       int i_am_root;
50288 +       int o;
50289 +       int num_childs = 0;
50290 +       int pid_fd = -1, fd;
50291 +       size_t i;
50292 +#ifdef _WIN32
50293 +       char *optarg = NULL;
50294 +#endif
50295 +
50296 +#ifdef HAVE_SIGACTION
50297 +       struct sigaction act;
50298 +#endif
50299 +#ifdef HAVE_GETRLIMIT
50300 +       struct rlimit rlim;
50301 +#endif
50302 +
50303 +#ifdef USE_ALARM
50304 +       struct itimerval interval;
50305 +
50306 +       interval.it_interval.tv_sec = 1;
50307 +       interval.it_interval.tv_usec = 0;
50308 +       interval.it_value.tv_sec = 1;
50309 +       interval.it_value.tv_usec = 0;
50310 +#endif
50311 +
50312 +       log_init();
50313 +       status_counter_init();
50314 +
50315 +       /* for nice %b handling in strfime() */
50316 +       setlocale(LC_TIME, "C");
50317 +       
50318 +       if (NULL == (srv = server_init())) {
50319 +               fprintf(stderr, "did this really happen?\n");
50320 +               return -1;
50321 +       }
50322 +
50323 +       /* init structs done */
50324 +
50325 +       srv->srvconf.port = 0;
50326 +#ifdef HAVE_GETUID
50327 +       i_am_root = (getuid() == 0);
50328 +#else
50329 +       i_am_root = 0;
50330 +#endif
50331 +       srv->srvconf.dont_daemonize = 0;
50332 +
50333 +       while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
50334 +               switch(o) {
50335 +               case 'f':
50336 +#ifdef _WIN32
50337 +                       /* evil HACK for windows, optarg is not set */
50338 +                       optarg = argv[optind-1];
50339 +#endif
50340 +                       if (config_read(srv, optarg)) {
50341 +                               server_free(srv);
50342 +                               return -1;
50343 +                       }
50344 +
50345 +                       break;
50346 +               case 'm':
50347 +                       buffer_copy_string(srv->srvconf.modules_dir, optarg);
50348 +                       break;
50349 +               case 'p': print_config = 1; break;
50350 +               case 't': test_config = 1; break;
50351 +               case 'D': srv->srvconf.dont_daemonize = 1; break;
50352 +               case 'v': show_version(); return 0;
50353 +               case 'V': show_features(); return 0;
50354 +               case 'h': show_help(); return 0;
50355 +               default:
50356 +                       show_help();
50357 +                       server_free(srv);
50358 +                       return -1;
50359 +               }
50360 +       }
50361 +
50362 +       if (!srv->config_storage) {
50363 +               log_error_write(srv, __FILE__, __LINE__, "s",
50364 +                               "No configuration available. Try using -f option.");
50365 +
50366 +               server_free(srv);
50367 +               return -1;
50368 +       }
50369 +
50370 +       if (print_config) {
50371 +               data_unset *dc = srv->config_context->data[0];
50372 +               if (dc) {
50373 +                       dc->print(dc, 0);
50374 +                       fprintf(stderr, "\n");
50375 +               } else {
50376 +                       /* shouldn't happend */
50377 +                       fprintf(stderr, "global config not found\n");
50378 +               }
50379 +       }
50380 +
50381 +       if (test_config) {
50382 +               printf("Syntax OK\n");
50383 +       }
50384 +
50385 +       if (test_config || print_config) {
50386 +               server_free(srv);
50387 +               return 0;
50388 +       }
50389 +
50390 +       /* close stdin and stdout, as they are not needed */
50391 +       /* move stdin to /dev/null */
50392 +       if (-1 != (fd = open("/dev/null", O_RDONLY))) {
50393 +               close(STDIN_FILENO);
50394 +               dup2(fd, STDIN_FILENO);
50395 +               close(fd);
50396 +       }
50397 +
50398 +       /* move stdout to /dev/null */
50399 +       if (-1 != (fd = open("/dev/null", O_WRONLY))) {
50400 +               close(STDOUT_FILENO);
50401 +               dup2(fd, STDOUT_FILENO);
50402 +               close(fd);
50403 +       }
50404 +
50405 +       if (0 != config_set_defaults(srv)) {
50406 +               log_error_write(srv, __FILE__, __LINE__, "s",
50407 +                               "setting default values failed");
50408 +               server_free(srv);
50409 +               return -1;
50410 +       }
50411 +
50412 +       /* UID handling */
50413 +#ifdef HAVE_GETUID
50414 +       if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
50415 +               /* we are setuid-root */
50416 +
50417 +               log_error_write(srv, __FILE__, __LINE__, "s",
50418 +                               "Are you nuts ? Don't apply a SUID bit to this binary");
50419 +
50420 +               server_free(srv);
50421 +               return -1;
50422 +       }
50423 +#endif
50424 +
50425 +       /* check document-root */
50426 +       if (srv->config_storage[0]->document_root->used <= 1) {
50427 +               log_error_write(srv, __FILE__, __LINE__, "s",
50428 +                               "document-root is not set\n");
50429 +
50430 +               server_free(srv);
50431 +
50432 +               return -1;
50433 +       }
50434 +
50435 +       if (plugins_load(srv)) {
50436 +               log_error_write(srv, __FILE__, __LINE__, "s",
50437 +                               "loading plugins finally failed");
50438 +
50439 +               plugins_free(srv);
50440 +               server_free(srv);
50441 +
50442 +               return -1;
50443 +       }
50444 +
50445 +#ifndef _WIN32
50446 +       /* open pid file BEFORE chroot */
50447 +       if (srv->srvconf.pid_file->used) {
50448 +               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))) {
50449 +                       struct stat st;
50450 +                       if (errno != EEXIST) {
50451 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
50452 +                                       "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
50453 +                               return -1;
50454 +                       }
50455 +
50456 +                       if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
50457 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
50458 +                                               "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
50459 +                       }
50460 +
50461 +                       if (!S_ISREG(st.st_mode)) {
50462 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
50463 +                                               "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
50464 +                               return -1;
50465 +                       }
50466 +
50467 +                       if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
50468 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
50469 +                                               "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
50470 +                               return -1;
50471 +                       }
50472 +               }
50473 +       }
50474 +#endif
50475 +       if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50476 +               /* select limits itself
50477                  *
50478                  * as it is a hard limit and will lead to a segfault we add some safety
50479                  * */
50480 -               srv->max_fds = FD_SETSIZE - 200;
50481 +        fprintf(stderr, "%s.%d: max parallel connections: %d\r\n", __FILE__, __LINE__, FD_SETSIZE);
50482 +               srv->max_fds = FD_SETSIZE - 4;
50483         } else {
50484                 srv->max_fds = 4096;
50485         }
50486 @@ -636,7 +1006,7 @@
50487  #ifdef HAVE_VALGRIND_VALGRIND_H
50488                 if (RUNNING_ON_VALGRIND) use_rlimit = 0;
50489  #endif
50490 -               
50491 +
50492  #ifdef HAVE_GETRLIMIT
50493                 if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
50494                         log_error_write(srv, __FILE__, __LINE__,
50495 @@ -644,13 +1014,13 @@
50496                                         strerror(errno));
50497                         return -1;
50498                 }
50499 -               
50500 +
50501                 if (use_rlimit && srv->srvconf.max_fds) {
50502                         /* set rlimits */
50503 -                       
50504 +
50505                         rlim.rlim_cur = srv->srvconf.max_fds;
50506                         rlim.rlim_max = srv->srvconf.max_fds;
50507 -                       
50508 +
50509                         if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
50510                                 log_error_write(srv, __FILE__, __LINE__,
50511                                                 "ss", "couldn't set 'max filedescriptors'",
50512 @@ -659,7 +1029,7 @@
50513                         }
50514                 }
50515  
50516 -               /* #372: solaris need some fds extra for devpoll */     
50517 +               /* #372: solaris need some fds extra for devpoll */
50518                 if (rlim.rlim_cur > 10) rlim.rlim_cur -= 10;
50519  
50520                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50521 @@ -677,33 +1047,33 @@
50522                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50523                         /* don't raise the limit above FD_SET_SIZE */
50524                         if (srv->max_fds > FD_SETSIZE - 200) {
50525 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
50526 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
50527                                                 "can't raise max filedescriptors above",  FD_SETSIZE - 200,
50528                                                 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
50529                                 return -1;
50530                         }
50531                 }
50532  
50533 -               
50534 +
50535  #ifdef HAVE_PWD_H
50536                 /* set user and group */
50537                 if (srv->srvconf.username->used) {
50538                         if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) {
50539 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
50540 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
50541                                                 "can't find username", srv->srvconf.username);
50542                                 return -1;
50543                         }
50544 -                       
50545 +
50546                         if (pwd->pw_uid == 0) {
50547                                 log_error_write(srv, __FILE__, __LINE__, "s",
50548                                                 "I will not set uid to 0\n");
50549                                 return -1;
50550                         }
50551                 }
50552 -               
50553 +
50554                 if (srv->srvconf.groupname->used) {
50555                         if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) {
50556 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
50557 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
50558                                         "can't find groupname", srv->srvconf.groupname);
50559                                 return -1;
50560                         }
50561 @@ -713,15 +1083,15 @@
50562                                 return -1;
50563                         }
50564                 }
50565 -#endif         
50566 +#endif
50567                 /* we need root-perms for port < 1024 */
50568                 if (0 != network_init(srv)) {
50569                         plugins_free(srv);
50570                         server_free(srv);
50571 -                       
50572 +
50573                         return -1;
50574                 }
50575 -#ifdef HAVE_CHROOT     
50576 +#ifdef HAVE_CHROOT
50577                 if (srv->srvconf.changeroot->used) {
50578                         tzset();
50579  
50580 @@ -761,7 +1131,7 @@
50581                 }
50582  
50583                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50584 -                       srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
50585 +                       srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 4 ? rlim.rlim_cur : FD_SETSIZE - 4;
50586                 } else {
50587                         srv->max_fds = rlim.rlim_cur;
50588                 }
50589 @@ -775,18 +1145,18 @@
50590  #endif
50591                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50592                         /* don't raise the limit above FD_SET_SIZE */
50593 -                       if (srv->max_fds > FD_SETSIZE - 200) {
50594 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
50595 -                                               "can't raise max filedescriptors above",  FD_SETSIZE - 200,
50596 +                       if (srv->max_fds > FD_SETSIZE - 4) {
50597 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
50598 +                                               "can't raise max filedescriptors above",  FD_SETSIZE - 4,
50599                                                 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
50600                                 return -1;
50601                         }
50602                 }
50603 -               
50604 +
50605                 if (0 != network_init(srv)) {
50606                         plugins_free(srv);
50607                         server_free(srv);
50608 -                       
50609 +
50610                         return -1;
50611                 }
50612         }
50613 @@ -802,25 +1172,27 @@
50614                 /* or use the default */
50615                 srv->max_conns = srv->max_fds;
50616         }
50617 -       
50618 +
50619         if (HANDLER_GO_ON != plugins_call_init(srv)) {
50620                 log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down.");
50621 -               
50622 +
50623                 plugins_free(srv);
50624                 network_close(srv);
50625                 server_free(srv);
50626 -               
50627 +
50628                 return -1;
50629         }
50630  
50631 -#ifdef HAVE_FORK       
50632 +#ifdef HAVE_FORK
50633         /* network is up, let's deamonize ourself */
50634         if (srv->srvconf.dont_daemonize == 0) daemonize();
50635  #endif
50636  
50637 +#ifdef HAVE_PWD_H
50638         srv->gid = getgid();
50639         srv->uid = getuid();
50640 -       
50641 +#endif
50642 +
50643         /* write pid file */
50644         if (pid_fd != -1) {
50645                 buffer_copy_long(srv->tmp_buf, getpid());
50646 @@ -829,17 +1201,17 @@
50647                 close(pid_fd);
50648                 pid_fd = -1;
50649         }
50650 -       
50651 +
50652         if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) {
50653                 log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down.");
50654 -               
50655 +
50656                 plugins_free(srv);
50657                 network_close(srv);
50658                 server_free(srv);
50659 -               
50660 +
50661                 return -1;
50662         }
50663 -       
50664 +
50665         /* dump unused config-keys */
50666         for (i = 0; i < srv->config_context->used; i++) {
50667                 array *config = ((data_config *)srv->config_context->data[i])->value;
50668 @@ -847,43 +1219,42 @@
50669  
50670                 for (j = 0; config && j < config->used; j++) {
50671                         data_unset *du = config->data[j];
50672 -                       
50673 +
50674                         /* all var.* is known as user defined variable */
50675                         if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) {
50676                                 continue;
50677                         }
50678  
50679                         if (NULL == array_get_element(srv->config_touched, du->key->ptr)) {
50680 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
50681 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
50682                                                 "WARNING: unknown config-key:",
50683                                                 du->key,
50684                                                 "(ignored)");
50685                         }
50686                 }
50687         }
50688 -       
50689 +
50690         if (srv->config_deprecated) {
50691 -               log_error_write(srv, __FILE__, __LINE__, "s", 
50692 +               log_error_write(srv, __FILE__, __LINE__, "s",
50693                                 "Configuration contains deprecated keys. Going down.");
50694 -               
50695 +
50696                 plugins_free(srv);
50697                 network_close(srv);
50698                 server_free(srv);
50699 -               
50700 +
50701                 return -1;
50702         }
50703 -       
50704 -       if (-1 == log_error_open(srv)) {
50705 -               log_error_write(srv, __FILE__, __LINE__, "s", 
50706 +
50707 +       if (-1 == log_error_open(srv->srvconf.errorlog_file, srv->srvconf.errorlog_use_syslog)) {
50708 +               log_error_write(srv, __FILE__, __LINE__, "s",
50709                                 "opening errorlog failed, dying");
50710 -               
50711 +
50712                 plugins_free(srv);
50713                 network_close(srv);
50714                 server_free(srv);
50715                 return -1;
50716         }
50717 -       
50718 -       
50719 +
50720  #ifdef HAVE_SIGACTION
50721         memset(&act, 0, sizeof(act));
50722         act.sa_handler = SIG_IGN;
50723 @@ -903,7 +1274,7 @@
50724         sigaction(SIGHUP,  &act, NULL);
50725         sigaction(SIGALRM, &act, NULL);
50726         sigaction(SIGCHLD, &act, NULL);
50727 -       
50728 +
50729  #elif defined(HAVE_SIGNAL)
50730         /* ignore the SIGPIPE from sendfile() */
50731         signal(SIGPIPE, SIG_IGN);
50732 @@ -914,20 +1285,20 @@
50733         signal(SIGCHLD,  signal_handler);
50734         signal(SIGINT,  signal_handler);
50735  #endif
50736 -       
50737 +
50738  #ifdef USE_ALARM
50739         signal(SIGALRM, signal_handler);
50740 -       
50741 +
50742         /* setup periodic timer (1 second) */
50743         if (setitimer(ITIMER_REAL, &interval, NULL)) {
50744                 log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed");
50745                 return -1;
50746         }
50747 -       
50748 +
50749         getitimer(ITIMER_REAL, &interval);
50750  #endif
50751  
50752 -#ifdef HAVE_FORK       
50753 +#ifdef HAVE_FORK
50754         /* start watcher and workers */
50755         num_childs = srv->srvconf.max_worker;
50756         if (num_childs > 0) {
50757 @@ -957,13 +1328,13 @@
50758         }
50759  #endif
50760  
50761 -       if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) {
50762 +       if (NULL == (srv->ev = fdevent_init(/*srv->max_fds + 1*/ 4096, srv->event_handler))) {
50763                 log_error_write(srv, __FILE__, __LINE__,
50764                                 "s", "fdevent_init failed");
50765                 return -1;
50766         }
50767 -       /* 
50768 -        * kqueue() is called here, select resets its internals, 
50769 +       /*
50770 +        * kqueue() is called here, select resets its internals,
50771          * all server sockets get their handlers
50772          *
50773          * */
50774 @@ -971,7 +1342,7 @@
50775                 plugins_free(srv);
50776                 network_close(srv);
50777                 server_free(srv);
50778 -               
50779 +
50780                 return -1;
50781         }
50782  
50783 @@ -986,17 +1357,17 @@
50784         /* setup FAM */
50785         if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
50786                 if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) {
50787 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
50788 +                       log_error_write(srv, __FILE__, __LINE__, "s",
50789                                          "could not open a fam connection, dieing.");
50790                         return -1;
50791                 }
50792  #ifdef HAVE_FAMNOEXISTS
50793                 FAMNoExists(srv->stat_cache->fam);
50794  #endif
50795 +               srv->stat_cache->sock->fd = FAMCONNECTION_GETFD(srv->stat_cache->fam);
50796  
50797 -               srv->stat_cache->fam_fcce_ndx = -1;
50798 -               fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL);
50799 -               fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN);
50800 +               fdevent_register(srv->ev, srv->stat_cache->sock, stat_cache_handle_fdevent, NULL);
50801 +               fdevent_event_add(srv->ev, srv->stat_cache->sock, FDEVENT_IN);
50802         }
50803  #endif
50804  
50805 @@ -1007,330 +1378,36 @@
50806  
50807         for (i = 0; i < srv->srv_sockets.used; i++) {
50808                 server_socket *srv_socket = srv->srv_sockets.ptr[i];
50809 -               if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) {
50810 +               if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->sock)) {
50811                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno));
50812                         return -1;
50813                 }
50814         }
50815  
50816 -       /* main-loop */
50817 -       while (!srv_shutdown) {
50818 -               int n;
50819 -               size_t ndx;
50820 -               time_t min_ts;
50821 -               
50822 -               if (handle_sig_hup) {
50823 -                       handler_t r;
50824 -                       
50825 -                       /* reset notification */
50826 -                       handle_sig_hup = 0;
50827 -                       
50828 -                       
50829 -                       /* cycle logfiles */
50830 -                       
50831 -                       switch(r = plugins_call_handle_sighup(srv)) {
50832 -                       case HANDLER_GO_ON:
50833 -                               break;
50834 -                       default:
50835 -                               log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
50836 -                               break;
50837 -                       }
50838 -                       
50839 -                       if (-1 == log_error_cycle(srv)) {
50840 -                               log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
50841 -                               
50842 -                               return -1;
50843 -                       }
50844 -               }
50845 -               
50846 -               if (handle_sig_alarm) {
50847 -                       /* a new second */
50848 -                       
50849 -#ifdef USE_ALARM
50850 -                       /* reset notification */
50851 -                       handle_sig_alarm = 0;
50852 -#endif
50853 -                       
50854 -                       /* get current time */
50855 -                       min_ts = time(NULL);
50856 -                       
50857 -                       if (min_ts != srv->cur_ts) {
50858 -                               int cs = 0;
50859 -                               connections *conns = srv->conns;
50860 -                               handler_t r;
50861 -                               
50862 -                               switch(r = plugins_call_handle_trigger(srv)) {
50863 -                               case HANDLER_GO_ON:
50864 -                                       break;
50865 -                               case HANDLER_ERROR:
50866 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
50867 -                                       break;
50868 -                               default:
50869 -                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
50870 -                                       break;
50871 -                               }
50872 -                               
50873 -                               /* trigger waitpid */
50874 -                               srv->cur_ts = min_ts;
50875 -                       
50876 -                               /* cleanup stat-cache */        
50877 -                               stat_cache_trigger_cleanup(srv);
50878 -                               /**
50879 -                                * check all connections for timeouts 
50880 -                                * 
50881 -                                */
50882 -                               for (ndx = 0; ndx < conns->used; ndx++) {
50883 -                                       int changed = 0;
50884 -                                       connection *con;
50885 -                                       int t_diff;
50886 -                                       
50887 -                                       con = conns->ptr[ndx];
50888 -
50889 -                                       if (con->state == CON_STATE_READ ||
50890 -                                           con->state == CON_STATE_READ_POST) {
50891 -                                               if (con->request_count == 1) {
50892 -                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
50893 -                                                               /* time - out */
50894 -#if 0
50895 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
50896 -                                                                               "connection closed - read-timeout:", con->fd);
50897 -#endif
50898 -                                                               connection_set_state(srv, con, CON_STATE_ERROR);
50899 -                                                               changed = 1;
50900 -                                                       }
50901 -                                               } else {
50902 -                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
50903 -                                                               /* time - out */
50904 -#if 0
50905 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
50906 -                                                                               "connection closed - read-timeout:", con->fd);
50907 -#endif
50908 -                                                               connection_set_state(srv, con, CON_STATE_ERROR);
50909 -                                                               changed = 1;
50910 -                                                       }
50911 -                                               }
50912 -                                       }
50913 -                                       
50914 -                                       if ((con->state == CON_STATE_WRITE) &&
50915 -                                           (con->write_request_ts != 0)) { 
50916 -#if 0
50917 -                                               if (srv->cur_ts - con->write_request_ts > 60) {
50918 -                                                       log_error_write(srv, __FILE__, __LINE__, "sdd", 
50919 -                                                                       "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
50920 -                                               }
50921 -#endif
50922 -                                               
50923 -                                               if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
50924 -                                                       /* time - out */
50925 -#if 1
50926 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsosds", 
50927 -                                                                       "NOTE: a request for",
50928 -                                                                       con->request.uri,
50929 -                                                                       "timed out after writing",
50930 -                                                                       con->bytes_written,
50931 -                                                                       "bytes. We waited",
50932 -                                                                       (int)con->conf.max_write_idle,
50933 -                                                                       "seconds. If this a problem increase server.max-write-idle");
50934 -#endif
50935 -                                                       connection_set_state(srv, con, CON_STATE_ERROR);
50936 -                                                       changed = 1;
50937 -                                               }
50938 -                                       }
50939 -                                       /* we don't like div by zero */
50940 -                                       if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
50941 -       
50942 -                                       if (con->traffic_limit_reached && 
50943 -                                           (con->conf.kbytes_per_second == 0 || 
50944 -                                            ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
50945 -                                               /* enable connection again */
50946 -                                               con->traffic_limit_reached = 0;
50947 -                                               
50948 -                                               changed = 1;
50949 -                                       }
50950 -                                       
50951 -                                       if (changed) {
50952 -                                               connection_state_machine(srv, con);
50953 -                                       }
50954 -                                       con->bytes_written_cur_second = 0;
50955 -                                       *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
50956 -                                       
50957 -#if 0
50958 -                                       if (cs == 0) {
50959 -                                               fprintf(stderr, "connection-state: ");
50960 -                                               cs = 1;
50961 -                                       }
50962 -                                       
50963 -                                       fprintf(stderr, "c[%d,%d]: %s ",
50964 -                                               con->fd,
50965 -                                               con->fcgi.fd,
50966 -                                               connection_get_state(con->state));
50967 -#endif
50968 -                               }
50969 -                               
50970 -                               if (cs == 1) fprintf(stderr, "\n");
50971 -                       }
50972 -               }
50973 -
50974 -               if (srv->sockets_disabled) {
50975 -                       /* our server sockets are disabled, why ? */
50976 -
50977 -                       if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
50978 -                           (srv->conns->used < srv->max_conns * 0.9) &&
50979 -                           (0 == graceful_shutdown)) {
50980 -                               for (i = 0; i < srv->srv_sockets.used; i++) {
50981 -                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
50982 -                                       fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
50983 -                               }
50984 -                       
50985 -                               log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
50986 -                       
50987 -                               srv->sockets_disabled = 0;
50988 -                       }
50989 -               } else {
50990 -                       if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
50991 -                           (srv->conns->used > srv->max_conns) || /* out of connections */
50992 -                           (graceful_shutdown)) { /* graceful_shutdown */ 
50993 -
50994 -                               /* disable server-fds */
50995 -                       
50996 -                               for (i = 0; i < srv->srv_sockets.used; i++) {
50997 -                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
50998 -                                       fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
50999 -
51000 -                                       if (graceful_shutdown) {
51001 -                                               /* we don't want this socket anymore,
51002 -                                                *
51003 -                                                * closing it right away will make it possible for
51004 -                                                * the next lighttpd to take over (graceful restart)
51005 -                                                *  */
51006 -
51007 -                                               fdevent_unregister(srv->ev, srv_socket->fd);
51008 -                                               close(srv_socket->fd);
51009 -                                               srv_socket->fd = -1;
51010 -
51011 -                                               /* network_close() will cleanup after us */
51012 -                                       }
51013 -                               }
51014 -               
51015 -                               if (graceful_shutdown) {
51016 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
51017 -                               } else if (srv->conns->used > srv->max_conns) {
51018 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
51019 -                               } else {
51020 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
51021 -                               }
51022 -                       
51023 -                               srv->sockets_disabled = 1;
51024 -                       }
51025 -               }
51026 +       lighty_mainloop(srv);
51027  
51028 -               if (graceful_shutdown && srv->conns->used == 0) {
51029 -                       /* we are in graceful shutdown phase and all connections are closed
51030 -                        * we are ready to terminate without harming anyone */
51031 -                       srv_shutdown = 1;
51032 -               }
51033 -               
51034 -               /* we still have some fds to share */
51035 -               if (srv->want_fds) { 
51036 -                       /* check the fdwaitqueue for waiting fds */
51037 -                       int free_fds = srv->max_fds - srv->cur_fds - 16;
51038 -                       connection *con;
51039 -                       
51040 -                       for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
51041 -                               connection_state_machine(srv, con);
51042 -                               
51043 -                               srv->want_fds--;
51044 -                       }
51045 -               }
51046 +       status_counter_free();
51047  
51048 -               if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
51049 -                       /* n is the number of events */
51050 -                       int revents;
51051 -                       int fd_ndx;
51052 -#if 0
51053 -                       if (n > 0) {
51054 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
51055 -                                               "polls:", n);
51056 -                       }
51057 -#endif                 
51058 -                       fd_ndx = -1;
51059 -                       do {
51060 -                               fdevent_handler handler;
51061 -                               void *context;
51062 -                               handler_t r;
51063 -                               
51064 -                               fd_ndx  = fdevent_event_next_fdndx (srv->ev, fd_ndx);
51065 -                               revents = fdevent_event_get_revent (srv->ev, fd_ndx);
51066 -                               fd      = fdevent_event_get_fd     (srv->ev, fd_ndx);
51067 -                               handler = fdevent_get_handler(srv->ev, fd);
51068 -                               context = fdevent_get_context(srv->ev, fd);
51069 -                               
51070 -                               /* connection_handle_fdevent needs a joblist_append */
51071 -#if 0
51072 -                               log_error_write(srv, __FILE__, __LINE__, "sdd", 
51073 -                                               "event for", fd, revents);
51074 -#endif                         
51075 -                               switch (r = (*handler)(srv, context, revents)) {
51076 -                               case HANDLER_FINISHED:
51077 -                               case HANDLER_GO_ON:
51078 -                               case HANDLER_WAIT_FOR_EVENT:
51079 -                               case HANDLER_WAIT_FOR_FD:
51080 -                                       break;
51081 -                               case HANDLER_ERROR:
51082 -                                       /* should never happen */
51083 -                                       SEGFAULT();
51084 -                                       break;
51085 -                               default:
51086 -                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
51087 -                                       break;
51088 -                               }
51089 -                       } while (--n > 0);
51090 -               } else if (n < 0 && errno != EINTR) {
51091 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
51092 -                                       "fdevent_poll failed:", 
51093 -                                       strerror(errno));
51094 -               }
51095 -               
51096 -               for (ndx = 0; ndx < srv->joblist->used; ndx++) {
51097 -                       connection *con = srv->joblist->ptr[ndx];
51098 -                       handler_t r;
51099 -                       
51100 -                       connection_state_machine(srv, con);
51101 -                       
51102 -                       switch(r = plugins_call_handle_joblist(srv, con)) {
51103 -                       case HANDLER_FINISHED:
51104 -                       case HANDLER_GO_ON:
51105 -                               break;
51106 -                       default:
51107 -                               log_error_write(srv, __FILE__, __LINE__, "d", r);
51108 -                               break;
51109 -                       }
51110 -                       
51111 -                       con->in_joblist = 0;
51112 -               }
51113 -               
51114 -               srv->joblist->used = 0;
51115 -       }
51116 -       
51117 -       if (srv->srvconf.pid_file->used &&
51118 +       if (0 == graceful_restart &&
51119 +           srv->srvconf.pid_file->used &&
51120             srv->srvconf.changeroot->used == 0) {
51121                 if (0 != unlink(srv->srvconf.pid_file->ptr)) {
51122                         if (errno != EACCES && errno != EPERM) {
51123 -                               log_error_write(srv, __FILE__, __LINE__, "sbds", 
51124 -                                               "unlink failed for:", 
51125 +                               log_error_write(srv, __FILE__, __LINE__, "sbds",
51126 +                                               "unlink failed for:",
51127                                                 srv->srvconf.pid_file,
51128                                                 errno,
51129                                                 strerror(errno));
51130                         }
51131                 }
51132         }
51133 -       
51134 +
51135         /* clean-up */
51136 -       log_error_close(srv);
51137         network_close(srv);
51138         connections_free(srv);
51139         plugins_free(srv);
51140         server_free(srv);
51141 -       
51142 +       log_free();
51143 +
51144         return 0;
51145  }
51146 --- ../lighttpd-1.4.11/src/settings.h   2005-08-11 01:26:41.000000000 +0300
51147 +++ lighttpd-1.4.12/src/settings.h      2006-07-16 00:26:04.000000000 +0300
51148 @@ -9,24 +9,24 @@
51149  /**
51150   * max size of a buffer which will just be reset
51151   * to ->used = 0 instead of really freeing the buffer
51152 - * 
51153 + *
51154   * 64kB (no real reason, just a guess)
51155   */
51156  #define BUFFER_MAX_REUSE_SIZE  (4 * 1024)
51157  
51158  /**
51159   * max size of the HTTP request header
51160 - * 
51161 + *
51162   * 32k should be enough for everything (just a guess)
51163 - * 
51164 + *
51165   */
51166  #define MAX_HTTP_REQUEST_HEADER  (32 * 1024)
51167  
51168 -typedef enum { HANDLER_UNSET, 
51169 -               HANDLER_GO_ON, 
51170 +typedef enum { HANDLER_UNSET,
51171 +               HANDLER_GO_ON,
51172                 HANDLER_FINISHED,
51173 -               HANDLER_COMEBACK, 
51174 -               HANDLER_WAIT_FOR_EVENT, 
51175 +               HANDLER_COMEBACK,
51176 +               HANDLER_WAIT_FOR_EVENT,
51177                 HANDLER_ERROR,
51178                 HANDLER_WAIT_FOR_FD
51179  } handler_t;
51180 --- ../lighttpd-1.4.11/src/spawn-fcgi.c 2006-03-07 14:18:10.000000000 +0200
51181 +++ lighttpd-1.4.12/src/spawn-fcgi.c    2006-07-16 00:26:04.000000000 +0300
51182 @@ -1,19 +1,16 @@
51183  #include <sys/types.h>
51184 -#include <sys/time.h>
51185  #include <sys/stat.h>
51186  
51187  #include <stdlib.h>
51188  #include <string.h>
51189  #include <errno.h>
51190  #include <stdio.h>
51191 -#include <unistd.h>
51192  #include <fcntl.h>
51193 -
51194 +#include <time.h>
51195  #ifdef HAVE_CONFIG_H
51196  #include "config.h"
51197  #endif
51198  
51199 -
51200  #ifdef HAVE_PWD_H
51201  #include <grp.h>
51202  #include <pwd.h>
51203 @@ -30,6 +27,7 @@
51204  #endif
51205  
51206  #include "sys-socket.h"
51207 +#include "sys-files.h"
51208  
51209  #ifdef HAVE_SYS_WAIT_H
51210  #include <sys/wait.h>
51211 @@ -45,28 +43,28 @@
51212         int fcgi_fd;
51213         int socket_type, status;
51214         struct timeval tv = { 0, 100 * 1000 };
51215 -       
51216 +
51217         struct sockaddr_un fcgi_addr_un;
51218         struct sockaddr_in fcgi_addr_in;
51219         struct sockaddr *fcgi_addr;
51220 -       
51221 +
51222         socklen_t servlen;
51223 -       
51224 +
51225         if (child_count < 2) {
51226                 child_count = 5;
51227         }
51228 -       
51229 +
51230         if (child_count > 256) {
51231                 child_count = 256;
51232         }
51233 -       
51234 -       
51235 +
51236 +
51237         if (unixsocket) {
51238                 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
51239 -               
51240 +
51241                 fcgi_addr_un.sun_family = AF_UNIX;
51242                 strcpy(fcgi_addr_un.sun_path, unixsocket);
51243 -               
51244 +
51245  #ifdef SUN_LEN
51246                 servlen = SUN_LEN(&fcgi_addr_un);
51247  #else
51248 @@ -84,50 +82,50 @@
51249                  }
51250                 fcgi_addr_in.sin_port = htons(port);
51251                 servlen = sizeof(fcgi_addr_in);
51252 -               
51253 +
51254                 socket_type = AF_INET;
51255                 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
51256         }
51257 -       
51258 +
51259         if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
51260 -               fprintf(stderr, "%s.%d\n", 
51261 +               fprintf(stderr, "%s.%d\n",
51262                         __FILE__, __LINE__);
51263                 return -1;
51264         }
51265 -       
51266 +
51267         if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
51268                 /* server is not up, spawn in  */
51269                 pid_t child;
51270                 int val;
51271 -               
51272 +
51273                 if (unixsocket) unlink(unixsocket);
51274 -               
51275 +
51276                 close(fcgi_fd);
51277 -               
51278 +
51279                 /* reopen socket */
51280                 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
51281 -                       fprintf(stderr, "%s.%d\n", 
51282 +                       fprintf(stderr, "%s.%d\n",
51283                                 __FILE__, __LINE__);
51284                         return -1;
51285                 }
51286  
51287                 val = 1;
51288                 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
51289 -                       fprintf(stderr, "%s.%d\n", 
51290 +                       fprintf(stderr, "%s.%d\n",
51291                                 __FILE__, __LINE__);
51292                         return -1;
51293                 }
51294  
51295                 /* create socket */
51296                 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
51297 -                       fprintf(stderr, "%s.%d: bind failed: %s\n", 
51298 +                       fprintf(stderr, "%s.%d: bind failed: %s\n",
51299                                 __FILE__, __LINE__,
51300                                 strerror(errno));
51301                         return -1;
51302                 }
51303 -               
51304 +
51305                 if (-1 == listen(fcgi_fd, 1024)) {
51306 -                       fprintf(stderr, "%s.%d: fd = -1\n", 
51307 +                       fprintf(stderr, "%s.%d: fd = -1\n",
51308                                 __FILE__, __LINE__);
51309                         return -1;
51310                 }
51311 @@ -137,42 +135,45 @@
51312                 } else {
51313                         child = 0;
51314                 }
51315 -               
51316 +
51317                 switch (child) {
51318                 case 0: {
51319                         char cgi_childs[64];
51320                         char *b;
51321 -                       
51322 +
51323                         int i = 0;
51324 -                       
51325 +
51326 +                       /* loose control terminal */
51327 +                       setsid();
51328 +
51329                         /* is save as we limit to 256 childs */
51330                         sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count);
51331 -                       
51332 +
51333                         if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
51334                                 close(FCGI_LISTENSOCK_FILENO);
51335                                 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
51336                                 close(fcgi_fd);
51337                         }
51338 -                       
51339 +
51340                         /* we don't need the client socket */
51341                         for (i = 3; i < 256; i++) {
51342                                 close(i);
51343                         }
51344 -                       
51345 +
51346                         /* create environment */
51347 -                       
51348 +
51349                         putenv(cgi_childs);
51350 -                       
51351 +
51352                         /* fork and replace shell */
51353                         b = malloc(strlen("exec ") + strlen(appPath) + 1);
51354                         strcpy(b, "exec ");
51355                         strcat(b, appPath);
51356 -                       
51357 +
51358                         /* exec the cgi */
51359                         execl("/bin/sh", "sh", "-c", b, NULL);
51360 -                       
51361 +
51362                         exit(errno);
51363 -                       
51364 +
51365                         break;
51366                 }
51367                 case -1:
51368 @@ -180,47 +181,47 @@
51369                         break;
51370                 default:
51371                         /* father */
51372 -                       
51373 +
51374                         /* wait */
51375                         select(0, NULL, NULL, NULL, &tv);
51376 -                       
51377 +
51378                         switch (waitpid(child, &status, WNOHANG)) {
51379                         case 0:
51380 -                               fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n", 
51381 +                               fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
51382                                         __FILE__, __LINE__,
51383                                         child);
51384 -                               
51385 +
51386                                 /* write pid file */
51387                                 if (pid_fd != -1) {
51388                                         /* assume a 32bit pid_t */
51389                                         char pidbuf[12];
51390 -                                       
51391 +
51392                                         snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child);
51393 -                                       
51394 +
51395                                         write(pid_fd, pidbuf, strlen(pidbuf));
51396                                         close(pid_fd);
51397                                         pid_fd = -1;
51398                                 }
51399 -                               
51400 +
51401                                 break;
51402                         case -1:
51403                                 break;
51404                         default:
51405                                 if (WIFEXITED(status)) {
51406 -                                       fprintf(stderr, "%s.%d: child exited with: %d, %s\n", 
51407 +                                       fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
51408                                                 __FILE__, __LINE__,
51409                                                 WEXITSTATUS(status), strerror(WEXITSTATUS(status)));
51410                                 } else if (WIFSIGNALED(status)) {
51411 -                                       fprintf(stderr, "%s.%d: child signaled: %d\n", 
51412 +                                       fprintf(stderr, "%s.%d: child signaled: %d\n",
51413                                                 __FILE__, __LINE__,
51414                                                 WTERMSIG(status));
51415                                 } else {
51416 -                                       fprintf(stderr, "%s.%d: child died somehow: %d\n", 
51417 +                                       fprintf(stderr, "%s.%d: child died somehow: %d\n",
51418                                                 __FILE__, __LINE__,
51419                                                 status);
51420                                 }
51421                         }
51422 -                               
51423 +
51424                         break;
51425                 }
51426         } else {
51427 @@ -228,16 +229,16 @@
51428                         __FILE__, __LINE__);
51429                 return -1;
51430         }
51431 -       
51432 +
51433         close(fcgi_fd);
51434 -       
51435 +
51436         return 0;
51437  }
51438  
51439  
51440  void show_version () {
51441         char *b = "spawn-fcgi" "-" PACKAGE_VERSION \
51442 -" - spawns fastcgi processes\n" 
51443 +" - spawns fastcgi processes\n"
51444  ;
51445         write(1, b, strlen(b));
51446  }
51447 @@ -265,7 +266,7 @@
51448  
51449  
51450  int main(int argc, char **argv) {
51451 -       char *fcgi_app = NULL, *changeroot = NULL, *username = NULL, 
51452 +       char *fcgi_app = NULL, *changeroot = NULL, *username = NULL,
51453                 *groupname = NULL, *unixsocket = NULL, *pid_file = NULL,
51454                  *addr = NULL;
51455         unsigned short port = 0;
51456 @@ -273,9 +274,9 @@
51457         int i_am_root, o;
51458         int pid_fd = -1;
51459         int nofork = 0;
51460 -       
51461 +
51462         i_am_root = (getuid() == 0);
51463 -       
51464 +
51465         while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) {
51466                 switch(o) {
51467                 case 'f': fcgi_app = optarg; break;
51468 @@ -290,137 +291,137 @@
51469                 case 'P': pid_file = optarg; /* PID file */ break;
51470                 case 'v': show_version(); return 0;
51471                 case 'h': show_help(); return 0;
51472 -               default: 
51473 +               default:
51474                         show_help();
51475                         return -1;
51476                 }
51477         }
51478 -       
51479 +
51480         if (fcgi_app == NULL || (port == 0 && unixsocket == NULL)) {
51481                 show_help();
51482                 return -1;
51483         }
51484 -           
51485 +
51486         if (unixsocket && port) {
51487 -               fprintf(stderr, "%s.%d: %s\n", 
51488 +               fprintf(stderr, "%s.%d: %s\n",
51489                         __FILE__, __LINE__,
51490                         "either a unix domain socket or a tcp-port, but not both\n");
51491 -               
51492 +
51493                 return -1;
51494         }
51495 -       
51496 +
51497         if (unixsocket && strlen(unixsocket) > UNIX_PATH_MAX - 1) {
51498 -               fprintf(stderr, "%s.%d: %s\n", 
51499 +               fprintf(stderr, "%s.%d: %s\n",
51500                         __FILE__, __LINE__,
51501                         "path of the unix socket is too long\n");
51502 -               
51503 +
51504                 return -1;
51505         }
51506  
51507         /* UID handling */
51508         if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
51509                 /* we are setuid-root */
51510 -               
51511 -               fprintf(stderr, "%s.%d: %s\n", 
51512 +
51513 +               fprintf(stderr, "%s.%d: %s\n",
51514                         __FILE__, __LINE__,
51515                         "Are you nuts ? Don't apply a SUID bit to this binary\n");
51516 -               
51517 +
51518                 return -1;
51519         }
51520 -       
51521 -       if (pid_file && 
51522 +
51523 +       if (pid_file &&
51524             (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)))) {
51525                 struct stat st;
51526                 if (errno != EEXIST) {
51527 -                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n", 
51528 +                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
51529                                 __FILE__, __LINE__,
51530                                 pid_file, strerror(errno));
51531 -                       
51532 +
51533                         return -1;
51534                 }
51535 -               
51536 +
51537                 /* ok, file exists */
51538 -               
51539 +
51540                 if (0 != stat(pid_file, &st)) {
51541 -                       fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n", 
51542 +                       fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n",
51543                                 __FILE__, __LINE__,
51544                                 pid_file, strerror(errno));
51545 -                       
51546 +
51547                         return -1;
51548                 }
51549 -               
51550 +
51551                 /* is it a regular file ? */
51552 -               
51553 +
51554                 if (!S_ISREG(st.st_mode)) {
51555 -                       fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n", 
51556 +                       fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n",
51557                                 __FILE__, __LINE__,
51558                                 pid_file);
51559 -                       
51560 +
51561                         return -1;
51562                 }
51563 -               
51564 +
51565                 if (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
51566 -                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n", 
51567 +                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
51568                                 __FILE__, __LINE__,
51569                                 pid_file, strerror(errno));
51570 -                       
51571 +
51572                         return -1;
51573                 }
51574         }
51575 -       
51576 +
51577         if (i_am_root) {
51578                 struct group *grp = NULL;
51579                 struct passwd *pwd = NULL;
51580 -               
51581 +
51582                 /* set user and group */
51583 -               
51584 +
51585                 if (username) {
51586                         if (NULL == (pwd = getpwnam(username))) {
51587 -                               fprintf(stderr, "%s.%d: %s, %s\n", 
51588 +                               fprintf(stderr, "%s.%d: %s, %s\n",
51589                                         __FILE__, __LINE__,
51590                                         "can't find username", username);
51591                                 return -1;
51592                         }
51593 -                       
51594 +
51595                         if (pwd->pw_uid == 0) {
51596 -                               fprintf(stderr, "%s.%d: %s\n", 
51597 +                               fprintf(stderr, "%s.%d: %s\n",
51598                                         __FILE__, __LINE__,
51599                                         "I will not set uid to 0\n");
51600                                 return -1;
51601                         }
51602                 }
51603 -               
51604 +
51605                 if (groupname) {
51606                         if (NULL == (grp = getgrnam(groupname))) {
51607 -                               fprintf(stderr, "%s.%d: %s %s\n", 
51608 +                               fprintf(stderr, "%s.%d: %s %s\n",
51609                                         __FILE__, __LINE__,
51610 -                                       "can't find groupname", 
51611 +                                       "can't find groupname",
51612                                         groupname);
51613                                 return -1;
51614                         }
51615                         if (grp->gr_gid == 0) {
51616 -                               fprintf(stderr, "%s.%d: %s\n", 
51617 +                               fprintf(stderr, "%s.%d: %s\n",
51618                                         __FILE__, __LINE__,
51619                                         "I will not set gid to 0\n");
51620                                 return -1;
51621                         }
51622                 }
51623 -               
51624 +
51625                 if (changeroot) {
51626                         if (-1 == chroot(changeroot)) {
51627 -                               fprintf(stderr, "%s.%d: %s %s\n", 
51628 +                               fprintf(stderr, "%s.%d: %s %s\n",
51629                                         __FILE__, __LINE__,
51630                                         "chroot failed: ", strerror(errno));
51631                                 return -1;
51632                         }
51633                         if (-1 == chdir("/")) {
51634 -                               fprintf(stderr, "%s.%d: %s %s\n", 
51635 +                               fprintf(stderr, "%s.%d: %s %s\n",
51636                                         __FILE__, __LINE__,
51637                                         "chdir failed: ", strerror(errno));
51638                                 return -1;
51639                         }
51640                 }
51641 -               
51642 +
51643                 /* drop root privs */
51644                 if (groupname) {
51645                         setgid(grp->gr_gid);
51646 @@ -428,7 +429,7 @@
51647                 }
51648                 if (username) setuid(pwd->pw_uid);
51649         }
51650 -       
51651 +
51652         return fcgi_spawn_connection(fcgi_app, addr, port, unixsocket, child_count, pid_fd, nofork);
51653  }
51654  #else
51655 --- ../lighttpd-1.4.11/src/splaytree.c  2005-09-12 21:51:28.000000000 +0300
51656 +++ lighttpd-1.4.12/src/splaytree.c     2006-07-16 00:26:03.000000000 +0300
51657 @@ -56,19 +56,19 @@
51658  
51659  #define node_size splaytree_size
51660  
51661 -/* Splay using the key i (which may or may not be in the tree.) 
51662 - * The starting root is t, and the tree used is defined by rat 
51663 +/* Splay using the key i (which may or may not be in the tree.)
51664 + * The starting root is t, and the tree used is defined by rat
51665   * size fields are maintained */
51666  splay_tree * splaytree_splay (splay_tree *t, int i) {
51667      splay_tree N, *l, *r, *y;
51668      int comp, root_size, l_size, r_size;
51669 -    
51670 +
51671      if (t == NULL) return t;
51672      N.left = N.right = NULL;
51673      l = r = &N;
51674      root_size = node_size(t);
51675      l_size = r_size = 0;
51676
51677 +
51678      for (;;) {
51679          comp = compare(i, t->key);
51680          if (comp < 0) {
51681 @@ -120,7 +120,7 @@
51682          y->size = r_size;
51683          r_size -= 1+node_size(y->right);
51684      }
51685
51686 +
51687      l->right = t->left;                                /* assemble */
51688      r->left = t->right;
51689      t->left = N.right;
51690 --- ../lighttpd-1.4.11/src/splaytree.h  2005-09-12 21:51:13.000000000 +0300
51691 +++ lighttpd-1.4.12/src/splaytree.h     2006-07-16 00:26:03.000000000 +0300
51692 @@ -19,6 +19,6 @@
51693  /* This macro returns the size of a node.  Unlike "x->size",     */
51694  /* it works even if x=NULL.  The test could be avoided by using  */
51695  /* a special version of NULL which was a real node with size 0.  */
51696
51697 +
51698  
51699  #endif
51700 --- ../lighttpd-1.4.11/src/stat_cache.c 2005-11-22 15:23:51.000000000 +0200
51701 +++ lighttpd-1.4.12/src/stat_cache.c    2006-07-18 13:03:40.000000000 +0300
51702 @@ -6,7 +6,6 @@
51703  #include <stdlib.h>
51704  #include <string.h>
51705  #include <errno.h>
51706 -#include <unistd.h>
51707  #include <stdio.h>
51708  #include <fcntl.h>
51709  #include <assert.h>
51710 @@ -25,19 +24,8 @@
51711  #endif
51712  
51713  #include "sys-mmap.h"
51714 -
51715 -/* NetBSD 1.3.x needs it */
51716 -#ifndef MAP_FAILED
51717 -# define MAP_FAILED -1
51718 -#endif
51719 -
51720 -#ifndef O_LARGEFILE
51721 -# define O_LARGEFILE 0
51722 -#endif
51723 -
51724 -#ifndef HAVE_LSTAT
51725 -#define lstat stat
51726 -#endif
51727 +#include "sys-files.h"
51728 +#include "sys-strings.h"
51729  
51730  #if 0
51731  /* enables debug code for testing if all nodes in the stat-cache as accessable */
51732 @@ -52,8 +40,8 @@
51733   *
51734   * if we get a change-event from FAM, we increment the version in the FAM->dir mapping
51735   *
51736 - * if the stat()-cache is queried we check if the version id for the directory is the 
51737 - * same and return immediatly. 
51738 + * if the stat()-cache is queried we check if the version id for the directory is the
51739 + * same and return immediatly.
51740   *
51741   *
51742   * What we need:
51743 @@ -62,17 +50,17 @@
51744   * - for each FAMRequest we have to find the version in the directory cache (index as userdata)
51745   *
51746   * stat <<-> directory <-> FAMRequest
51747 - * 
51748 - * if file is deleted, directory is dirty, file is rechecked ... 
51749 + *
51750 + * if file is deleted, directory is dirty, file is rechecked ...
51751   * if directory is deleted, directory mapping is removed
51752 - *  
51753 + *
51754   * */
51755  
51756  #ifdef HAVE_FAM_H
51757  typedef struct {
51758         FAMRequest *req;
51759         FAMConnection *fc;
51760 -       
51761 +
51762         buffer *name;
51763  
51764         int version;
51765 @@ -83,16 +71,16 @@
51766   * - we need a hash
51767   * - the hash-key is used as sorting criteria for a tree
51768   * - a splay-tree is used as we can use the caching effect of it
51769 - */ 
51770 + */
51771  
51772  /* we want to cleanup the stat-cache every few seconds, let's say 10
51773   *
51774   * - remove entries which are outdated since 30s
51775   * - remove entries which are fresh but havn't been used since 60s
51776   * - if we don't have a stat-cache entry for a directory, release it from the monitor
51777 - */ 
51778 + */
51779  
51780 -#ifdef DEBUG_STAT_CACHE        
51781 +#ifdef DEBUG_STAT_CACHE
51782  typedef struct {
51783         int *ptr;
51784  
51785 @@ -105,15 +93,16 @@
51786  
51787  stat_cache *stat_cache_init(void) {
51788         stat_cache *fc = NULL;
51789 -       
51790 +
51791         fc = calloc(1, sizeof(*fc));
51792 -       
51793 +
51794         fc->dir_name = buffer_init();
51795  #ifdef HAVE_FAM_H
51796         fc->fam = calloc(1, sizeof(*fc->fam));
51797 +       fc->sock = iosocket_init();
51798  #endif
51799  
51800 -#ifdef DEBUG_STAT_CACHE        
51801 +#ifdef DEBUG_STAT_CACHE
51802         ctrl.size = 0;
51803  #endif
51804  
51805 @@ -122,24 +111,24 @@
51806  
51807  static stat_cache_entry * stat_cache_entry_init(void) {
51808         stat_cache_entry *sce = NULL;
51809 -       
51810 +
51811         sce = calloc(1, sizeof(*sce));
51812 -       
51813 +
51814         sce->name = buffer_init();
51815         sce->etag = buffer_init();
51816         sce->content_type = buffer_init();
51817 -       
51818 +
51819         return sce;
51820  }
51821  
51822  static void stat_cache_entry_free(void *data) {
51823         stat_cache_entry *sce = data;
51824         if (!sce) return;
51825 -       
51826 +
51827         buffer_free(sce->etag);
51828         buffer_free(sce->name);
51829         buffer_free(sce->content_type);
51830 -       
51831 +
51832         free(sce);
51833  }
51834  
51835 @@ -148,22 +137,22 @@
51836         fam_dir_entry *fam_dir = NULL;
51837  
51838         fam_dir = calloc(1, sizeof(*fam_dir));
51839 -       
51840 +
51841         fam_dir->name = buffer_init();
51842 -       
51843 +
51844         return fam_dir;
51845  }
51846  
51847  static void fam_dir_entry_free(void *data) {
51848         fam_dir_entry *fam_dir = data;
51849 -       
51850 +
51851         if (!fam_dir) return;
51852 -       
51853 +
51854         FAMCancelMonitor(fam_dir->fc, fam_dir->req);
51855 -       
51856 +
51857         buffer_free(fam_dir->name);
51858         free(fam_dir->req);
51859 -       
51860 +
51861         free(fam_dir);
51862  }
51863  #endif
51864 @@ -174,7 +163,7 @@
51865                 splay_tree *node = sc->files;
51866  
51867                 osize = sc->files->size;
51868 -                       
51869 +
51870                 stat_cache_entry_free(node->data);
51871                 sc->files = splaytree_delete(sc->files, node->key);
51872  
51873 @@ -187,12 +176,12 @@
51874         while (sc->dirs) {
51875                 int osize;
51876                 splay_tree *node = sc->dirs;
51877 -               
51878 +
51879                 osize = sc->dirs->size;
51880  
51881                 fam_dir_entry_free(node->data);
51882                 sc->dirs = splaytree_delete(sc->dirs, node->key);
51883 -               
51884 +
51885                 if (osize == 1) {
51886                         assert(NULL == sc->dirs);
51887                 } else {
51888 @@ -202,6 +191,7 @@
51889  
51890         if (sc->fam) {
51891                 FAMClose(sc->fam);
51892 +               iosocket_free(sc->sock);
51893                 free(sc->fam);
51894         }
51895  #endif
51896 @@ -212,7 +202,7 @@
51897  static int stat_cache_attr_get(buffer *buf, char *name) {
51898         int attrlen;
51899         int ret;
51900 -       
51901 +
51902         attrlen = 1024;
51903         buffer_prepare_copy(buf, attrlen);
51904         attrlen--;
51905 @@ -251,15 +241,15 @@
51906             sc->fam) {
51907  
51908                 events = FAMPending(sc->fam);
51909 -       
51910 +
51911                 for (i = 0; i < events; i++) {
51912                         FAMEvent fe;
51913                         fam_dir_entry *fam_dir;
51914                         splay_tree *node;
51915                         int ndx;
51916 -               
51917 +
51918                         FAMNextEvent(sc->fam, &fe);
51919 -       
51920 +
51921                         /* handle event */
51922  
51923                         switch(fe.code) {
51924 @@ -280,7 +270,7 @@
51925  
51926                                 sc->dirs = splaytree_splay(sc->dirs, ndx);
51927                                 node = sc->dirs;
51928 -                       
51929 +
51930                                 if (node && (node->key == ndx)) {
51931                                         int osize = splaytree_size(sc->dirs);
51932  
51933 @@ -298,17 +288,15 @@
51934  
51935         if (revent & FDEVENT_HUP) {
51936                 /* fam closed the connection */
51937 -               srv->stat_cache->fam_fcce_ndx = -1;
51938 -
51939 -               fdevent_event_del(srv->ev, &(sc->fam_fcce_ndx), FAMCONNECTION_GETFD(sc->fam));
51940 -               fdevent_unregister(srv->ev, FAMCONNECTION_GETFD(sc->fam));
51941 +               fdevent_event_del(srv->ev, sc->sock);
51942 +               fdevent_unregister(srv->ev, sc->sock);
51943  
51944                 FAMClose(sc->fam);
51945                 free(sc->fam);
51946  
51947                 sc->fam = NULL;
51948         }
51949 -       
51950 +
51951         return HANDLER_GO_ON;
51952  }
51953  
51954 @@ -332,7 +320,7 @@
51955   *
51956   *
51957   *
51958 - * returns: 
51959 + * returns:
51960   *  - HANDLER_FINISHED on cache-miss (don't forget to reopen the file)
51961   *  - HANDLER_ERROR on stat() failed -> see errno for problem
51962   */
51963 @@ -348,16 +336,16 @@
51964         struct stat st;
51965         size_t k;
51966         int fd;
51967 -#ifdef DEBUG_STAT_CACHE        
51968 +#ifdef DEBUG_STAT_CACHE
51969         size_t i;
51970  #endif
51971  
51972         int file_ndx;
51973         splay_tree *file_node = NULL;
51974  
51975 -       *ret_sce = NULL; 
51976 +       *ret_sce = NULL;
51977  
51978 -       /* 
51979 +       /*
51980          * check if the directory for this file has changed
51981          */
51982  
51983 @@ -366,23 +354,23 @@
51984         file_ndx = hashme(name);
51985         sc->files = splaytree_splay(sc->files, file_ndx);
51986  
51987 -#ifdef DEBUG_STAT_CACHE        
51988 +#ifdef DEBUG_STAT_CACHE
51989         for (i = 0; i < ctrl.used; i++) {
51990                 if (ctrl.ptr[i] == file_ndx) break;
51991         }
51992  #endif
51993  
51994         if (sc->files && (sc->files->key == file_ndx)) {
51995 -#ifdef DEBUG_STAT_CACHE        
51996 +#ifdef DEBUG_STAT_CACHE
51997                 /* it was in the cache */
51998                 assert(i < ctrl.used);
51999  #endif
52000 -               
52001 -               /* we have seen this file already and 
52002 +
52003 +               /* we have seen this file already and
52004                  * don't stat() it again in the same second */
52005  
52006                 file_node = sc->files;
52007 -               
52008 +
52009                 sce = file_node->data;
52010  
52011                 /* check if the name is the same, we might have a collision */
52012 @@ -390,7 +378,7 @@
52013                 if (buffer_is_equal(name, sce->name)) {
52014                         if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) {
52015                                 if (sce->stat_ts == srv->cur_ts) {
52016 -                                       *ret_sce = sce; 
52017 +                                       *ret_sce = sce;
52018                                         return HANDLER_GO_ON;
52019                                 }
52020                         }
52021 @@ -400,15 +388,15 @@
52022                          * file_node is used by the FAM check below to see if we know this file
52023                          * and if we can save a stat().
52024                          *
52025 -                        * BUT, the sce is not reset here as the entry into the cache is ok, we 
52026 +                        * BUT, the sce is not reset here as the entry into the cache is ok, we
52027                          * it is just not pointing to our requested file.
52028 -                        * 
52029 +                        *
52030                          *  */
52031  
52032                         file_node = NULL;
52033                 }
52034         } else {
52035 -#ifdef DEBUG_STAT_CACHE        
52036 +#ifdef DEBUG_STAT_CACHE
52037                 if (i != ctrl.used) {
52038                         fprintf(stderr, "%s.%d: %08x was already inserted but not found in cache, %s\n", __FILE__, __LINE__, file_ndx, name->ptr);
52039                 }
52040 @@ -424,23 +412,23 @@
52041                 }
52042  
52043                 dir_ndx = hashme(sc->dir_name);
52044 -               
52045 +
52046                 sc->dirs = splaytree_splay(sc->dirs, dir_ndx);
52047 -               
52048 +
52049                 if (sc->dirs && (sc->dirs->key == dir_ndx)) {
52050                         dir_node = sc->dirs;
52051                 }
52052 -               
52053 +
52054                 if (dir_node && file_node) {
52055                         /* we found a file */
52056 -                       
52057 +
52058                         sce = file_node->data;
52059                         fam_dir = dir_node->data;
52060 -                       
52061 +
52062                         if (fam_dir->version == sce->dir_version) {
52063                                 /* the stat()-cache entry is still ok */
52064 -                               
52065 -                               *ret_sce = sce; 
52066 +
52067 +                               *ret_sce = sce;
52068                                 return HANDLER_GO_ON;
52069                         }
52070                 }
52071 @@ -448,7 +436,7 @@
52072  #endif
52073  
52074         /*
52075 -        * *lol* 
52076 +        * *lol*
52077          * - open() + fstat() on a named-pipe results in a (intended) hang.
52078          * - stat() if regualar file + open() to see if we can read from it is better
52079          *
52080 @@ -469,16 +457,16 @@
52081  
52082         if (NULL == sce) {
52083                 int osize = 0;
52084 -                      
52085 +
52086                 if (sc->files) {
52087                         osize = sc->files->size;
52088                 }
52089  
52090                 sce = stat_cache_entry_init();
52091                 buffer_copy_string_buffer(sce->name, name);
52092 -               
52093 -               sc->files = splaytree_insert(sc->files, file_ndx, sce); 
52094 -#ifdef DEBUG_STAT_CACHE        
52095 +
52096 +               sc->files = splaytree_insert(sc->files, file_ndx, sce);
52097 +#ifdef DEBUG_STAT_CACHE
52098                 if (ctrl.size == 0) {
52099                         ctrl.size = 16;
52100                         ctrl.used = 0;
52101 @@ -499,29 +487,29 @@
52102         sce->st = st;
52103         sce->stat_ts = srv->cur_ts;
52104  
52105 -       /* catch the obvious symlinks 
52106 +       /* catch the obvious symlinks
52107          *
52108          * this is not a secure check as we still have a race-condition between
52109 -        * the stat() and the open. We can only solve this by 
52110 +        * the stat() and the open. We can only solve this by
52111          * 1. open() the file
52112          * 2. fstat() the fd
52113          *
52114          * and keeping the file open for the rest of the time. But this can
52115          * only be done at network level.
52116 -        * 
52117 +        *
52118          * */
52119         if (S_ISLNK(st.st_mode) && !con->conf.follow_symlink) {
52120                 return HANDLER_ERROR;
52121         }
52122  
52123 -       if (S_ISREG(st.st_mode)) {      
52124 +       if (S_ISREG(st.st_mode)) {
52125                 /* determine mimetype */
52126                 buffer_reset(sce->content_type);
52127 -               
52128 +
52129                 for (k = 0; k < con->conf.mimetypes->used; k++) {
52130                         data_string *ds = (data_string *)con->conf.mimetypes->data[k];
52131                         buffer *type = ds->key;
52132 -               
52133 +
52134                         if (type->used == 0) continue;
52135  
52136                         /* check if the right side is the same */
52137 @@ -538,8 +526,10 @@
52138                         stat_cache_attr_get(sce->content_type, name->ptr);
52139                 }
52140  #endif
52141 +       } else if (S_ISDIR(st.st_mode)) {
52142 +               etag_create(sce->etag, &(sce->st));
52143         }
52144 -               
52145 +
52146  #ifdef HAVE_FAM_H
52147         if (sc->fam &&
52148             (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM)) {
52149 @@ -549,19 +539,19 @@
52150                         fam_dir->fc = sc->fam;
52151  
52152                         buffer_copy_string_buffer(fam_dir->name, sc->dir_name);
52153 -                       
52154 +
52155                         fam_dir->version = 1;
52156 -                       
52157 +
52158                         fam_dir->req = calloc(1, sizeof(FAMRequest));
52159 -                       
52160 -                       if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr, 
52161 +
52162 +                       if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr,
52163                                                      fam_dir->req, fam_dir)) {
52164 -                               
52165 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
52166 -                                               "monitoring dir failed:", 
52167 -                                               fam_dir->name, 
52168 +
52169 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
52170 +                                               "monitoring dir failed:",
52171 +                                               fam_dir->name,
52172                                                 FamErrlist[FAMErrno]);
52173 -                               
52174 +
52175                                 fam_dir_entry_free(fam_dir);
52176                         } else {
52177                                 int osize = 0;
52178 @@ -570,7 +560,7 @@
52179                                         osize = sc->dirs->size;
52180                                 }
52181  
52182 -                               sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir); 
52183 +                               sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir);
52184                                 assert(sc->dirs);
52185                                 assert(sc->dirs->data == fam_dir);
52186                                 assert(osize == (sc->dirs->size - 1));
52187 @@ -578,9 +568,9 @@
52188                 } else {
52189                         fam_dir = dir_node->data;
52190                 }
52191 -               
52192 +
52193                 /* bind the fam_fc to the stat() cache entry */
52194 -                       
52195 +
52196                 if (fam_dir) {
52197                         sce->dir_version = fam_dir->version;
52198                         sce->dir_ndx     = dir_ndx;
52199 @@ -594,11 +584,11 @@
52200  }
52201  
52202  /**
52203 - * remove stat() from cache which havn't been stat()ed for 
52204 + * remove stat() from cache which havn't been stat()ed for
52205   * more than 10 seconds
52206 - * 
52207   *
52208 - * walk though the stat-cache, collect the ids which are too old 
52209 + *
52210 + * walk though the stat-cache, collect the ids which are too old
52211   * and remove them in a second loop
52212   */
52213  
52214 @@ -639,9 +629,9 @@
52215                 sc->files = splaytree_splay(sc->files, ndx);
52216  
52217                 node = sc->files;
52218 -               
52219 +
52220                 if (node && (node->key == ndx)) {
52221 -#ifdef DEBUG_STAT_CACHE        
52222 +#ifdef DEBUG_STAT_CACHE
52223                         size_t j;
52224                         int osize = splaytree_size(sc->files);
52225                         stat_cache_entry *sce = node->data;
52226 @@ -649,7 +639,7 @@
52227                         stat_cache_entry_free(node->data);
52228                         sc->files = splaytree_delete(sc->files, ndx);
52229  
52230 -#ifdef DEBUG_STAT_CACHE        
52231 +#ifdef DEBUG_STAT_CACHE
52232                         for (j = 0; j < ctrl.used; j++) {
52233                                 if (ctrl.ptr[j] == ndx) {
52234                                         ctrl.ptr[j] = ctrl.ptr[--ctrl.used];
52235 --- ../lighttpd-1.4.11/src/status_counter.c     1970-01-01 03:00:00.000000000 +0300
52236 +++ lighttpd-1.4.12/src/status_counter.c        2006-07-19 20:02:55.000000000 +0300
52237 @@ -0,0 +1,75 @@
52238 +#include <stdlib.h>
52239 +
52240 +#include "status_counter.h"
52241 +/**
52242 + * The status array can carry all the status information you want
52243 + * the key to the array is <module-prefix>.<name>
52244 + * and the values are counters
52245 + *
52246 + * example:
52247 + *   fastcgi.backends        = 10
52248 + *   fastcgi.active-backends = 6
52249 + *   fastcgi.backend.<key>.load = 24
52250 + *   fastcgi.backend.<key>....
52251 + *
52252 + *   fastcgi.backend.<key>.disconnects = ...
52253 + */
52254 +
52255 +static array *counters = NULL;
52256 +
52257 +void status_counter_init(void) {
52258 +       counters = array_init();
52259 +}
52260 +void status_counter_free(void) {
52261 +       array_free(counters);
52262 +}
52263 +
52264 +array *status_counter_get_array(void) {
52265 +       return counters;
52266 +}
52267 +
52268 +data_integer *status_counter_get_counter(const char *s, size_t len) {
52269 +       data_integer *di;
52270 +       array *status = status_counter_get_array();
52271 +
52272 +       if (NULL == (di = (data_integer *)array_get_element(status, s))) {
52273 +               /* not found, create it */
52274 +
52275 +               if (NULL == (di = (data_integer *)array_get_unused_element(status, TYPE_INTEGER))) {
52276 +                       di = data_integer_init();
52277 +               }
52278 +               buffer_copy_string_len(di->key, s, len);
52279 +               di->value = 0;
52280 +
52281 +               array_insert_unique(status, (data_unset *)di);
52282 +       }
52283 +       return di;
52284 +}
52285 +
52286 +/* dummies of the statistic framework functions
52287 + * they will be moved to a statistics.c later */
52288 +int status_counter_inc(const char *s, size_t len) {
52289 +       data_integer *di = status_counter_get_counter(s, len);
52290 +
52291 +       di->value++;
52292 +
52293 +       return 0;
52294 +}
52295 +
52296 +int status_counter_dec(const char *s, size_t len) {
52297 +       data_integer *di = status_counter_get_counter(s, len);
52298 +
52299 +       if (di->value > 0) di->value--;
52300 +
52301 +       return 0;
52302 +}
52303 +
52304 +int status_counter_set(const char *s, size_t len, int val) {
52305 +       data_integer *di = status_counter_get_counter(s, len);
52306 +
52307 +       di->value = val;
52308 +
52309 +       return 0;
52310 +}
52311 +
52312 +
52313 --- ../lighttpd-1.4.11/src/status_counter.h     1970-01-01 03:00:00.000000000 +0300
52314 +++ lighttpd-1.4.12/src/status_counter.h        2006-07-19 20:02:55.000000000 +0300
52315 @@ -0,0 +1,16 @@
52316 +#ifndef _STATUS_COUNTER_H_
52317 +#define _STATUS_COUNTER_H_
52318 +
52319 +#include <sys/types.h>
52320 +
52321 +#include "array.h"
52322 +
52323 +void status_counter_init(void);
52324 +void status_counter_free(void);
52325 +array *status_counter_get_array(void);
52326 +data_integer *status_counter_get_counter(const char *s, size_t len);
52327 +int status_counter_inc(const char *s, size_t len);
52328 +int status_counter_dec(const char *s, size_t len);
52329 +int status_counter_set(const char *s, size_t len, int val);
52330 +
52331 +#endif 
52332 --- ../lighttpd-1.4.11/src/stream.c     2005-09-23 21:50:15.000000000 +0300
52333 +++ lighttpd-1.4.12/src/stream.c        2006-07-16 00:26:04.000000000 +0300
52334 @@ -1,7 +1,6 @@
52335  #include <sys/types.h>
52336  #include <sys/stat.h>
52337  
52338 -#include <unistd.h> 
52339  #include <fcntl.h>
52340  
52341  #include "stream.h"
52342 @@ -10,6 +9,7 @@
52343  #endif
52344  
52345  #include "sys-mmap.h"
52346 +#include "sys-files.h"
52347  
52348  #ifndef O_BINARY
52349  # define O_BINARY 0
52350 @@ -19,39 +19,39 @@
52351         struct stat st;
52352  #ifdef HAVE_MMAP
52353         int fd;
52354 -#elif defined __WIN32
52355 +#elif defined _WIN32
52356         HANDLE *fh, *mh;
52357         void *p;
52358  #endif
52359  
52360         f->start = NULL;
52361 -       
52362 +
52363         if (-1 == stat(fn->ptr, &st)) {
52364                 return -1;
52365         }
52366 -       
52367 +
52368         f->size = st.st_size;
52369  
52370  #ifdef HAVE_MMAP
52371         if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY))) {
52372                 return -1;
52373         }
52374 -       
52375 +
52376         f->start = mmap(0, f->size, PROT_READ, MAP_SHARED, fd, 0);
52377 -       
52378 +
52379         close(fd);
52380 -       
52381 +
52382         if (MAP_FAILED == f->start) {
52383                 return -1;
52384         }
52385  
52386 -#elif defined __WIN32
52387 -       fh = CreateFile(fn->ptr, 
52388 -                       GENERIC_READ, 
52389 -                       FILE_SHARE_READ, 
52390 -                       NULL, 
52391 -                       OPEN_EXISTING, 
52392 -                       FILE_ATTRIBUTE_READONLY, 
52393 +#elif defined _WIN32
52394 +       fh = CreateFile(fn->ptr,
52395 +                       GENERIC_READ,
52396 +                       FILE_SHARE_READ,
52397 +                       NULL,
52398 +                       OPEN_EXISTING,
52399 +                       FILE_ATTRIBUTE_READONLY,
52400                         NULL);
52401  
52402         if (!fh) return -1;
52403 @@ -66,7 +66,7 @@
52404         if (!mh) {
52405                 LPVOID lpMsgBuf;
52406                 FormatMessage(
52407 -                       FORMAT_MESSAGE_ALLOCATE_BUFFER | 
52408 +                       FORMAT_MESSAGE_ALLOCATE_BUFFER |
52409                         FORMAT_MESSAGE_FROM_SYSTEM,
52410                         NULL,
52411                         GetLastError(),
52412 @@ -76,7 +76,7 @@
52413  
52414                 return -1;
52415         }
52416 -       
52417 +
52418         p = MapViewOfFile(mh,
52419                         FILE_MAP_READ,
52420                         0,
52421 @@ -87,9 +87,9 @@
52422  
52423         f->start = p;
52424  #else
52425 -# error no mmap found  
52426 +# error no mmap found
52427  #endif
52428 -       
52429 +
52430         return 0;
52431  }
52432  
52433 --- ../lighttpd-1.4.11/src/sys-files.h  1970-01-01 03:00:00.000000000 +0300
52434 +++ lighttpd-1.4.12/src/sys-files.h     2006-07-16 00:26:04.000000000 +0300
52435 @@ -0,0 +1,67 @@
52436 +#ifndef _SYS_FILES_H_
52437 +#define _SYS_FILES_H_
52438 +
52439 +#define DIR_SEPERATOR_UNIX '/'
52440 +#define DIR_SEPERATOR_WIN '\\'
52441 +
52442 +#ifdef _WIN32
52443 +#include <windows.h>
52444 +#include <io.h>     /* open */
52445 +#include <direct.h> /* chdir */
52446 +
52447 +#include "buffer.h"
52448 +
52449 +#define DIR_SEPERATOR DIR_SEPERATOR_WIN
52450 +
52451 +#define __S_ISTYPE(mode, mask)  (((mode) & _S_IFMT) == (mask))
52452 +
52453 +#define S_ISDIR(mode)    __S_ISTYPE((mode), _S_IFDIR)
52454 +#define S_ISCHR(mode)    __S_ISTYPE((mode), _S_IFCHR)
52455 +#define S_ISBLK(mode)    __S_ISTYPE((mode), _S_IFBLK)
52456 +#define S_ISREG(mode)    __S_ISTYPE((mode), _S_IFREG)
52457 +/* we don't support symlinks */
52458 +#define S_ISLNK(mode)    0
52459 +
52460 +#define lstat stat
52461 +#define mkstemp mktemp
52462 +#define mkdir(x, y) mkdir(x)
52463 +
52464 +struct dirent {
52465 +    const char *d_name;
52466 +};
52467 +
52468 +typedef struct {
52469 +    HANDLE h;
52470 +    WIN32_FIND_DATA finddata;
52471 +    struct dirent dent;
52472 +} DIR;
52473 +
52474 +DIR *opendir(const char *dn);
52475 +struct dirent *readdir(DIR *d);
52476 +void closedir(DIR *d);
52477 +
52478 +buffer *filename_unix2local(buffer *b);
52479 +buffer *pathname_unix2local(buffer *b);
52480 +
52481 +#else
52482 +#include <unistd.h>
52483 +#include <dirent.h>
52484 +
52485 +#define DIR_SEPERATOR DIR_SEPERATOR_UNIX
52486 +
52487 +#define filename_unix2local(x) (x)
52488 +#define pathname_unix2local(x) (x)
52489 +#endif
52490 +
52491 +#define PATHNAME_APPEND_SLASH(x) \
52492 +       if (x->used > 1 && x->ptr[x->used - 2] != DIR_SEPERATOR) { \
52493 +        char sl[2] = { DIR_SEPERATOR, 0 }; \
52494 +        BUFFER_APPEND_STRING_CONST(x, sl); \
52495 +    }
52496 +
52497 +#ifndef O_LARGEFILE
52498 +# define O_LARGEFILE 0
52499 +#endif
52500 +
52501 +#endif
52502 +
52503 --- ../lighttpd-1.4.11/src/sys-mmap.h   2005-08-11 01:26:34.000000000 +0300
52504 +++ lighttpd-1.4.12/src/sys-mmap.h      2006-07-16 00:26:04.000000000 +0300
52505 @@ -1,7 +1,7 @@
52506  #ifndef WIN32_MMAP_H
52507  #define WIN32_MMAP_H
52508  
52509 -#ifdef __WIN32
52510 +#ifdef _WIN32
52511  
52512  #define MAP_FAILED -1
52513  #define PROT_SHARED 0
52514 --- ../lighttpd-1.4.11/src/sys-process.h        1970-01-01 03:00:00.000000000 +0300
52515 +++ lighttpd-1.4.12/src/sys-process.h   2006-07-16 00:26:04.000000000 +0300
52516 @@ -0,0 +1,17 @@
52517 +#ifndef _SYS_PROCESS_H_
52518 +#define _SYS_PROCESS_H_
52519 +
52520 +#ifdef _WIN32
52521 +#include <process.h>
52522 +#define pid_t int
52523 +/* win32 has no fork() */
52524 +#define kill(x, y)
52525 +#define getpid() 0
52526 +
52527 +#else
52528 +#include <sys/wait.h>
52529 +#include <unistd.h>
52530 +#endif
52531 +
52532 +#endif
52533 +
52534 --- ../lighttpd-1.4.11/src/sys-socket.h 2005-08-11 01:26:39.000000000 +0300
52535 +++ lighttpd-1.4.12/src/sys-socket.h    2006-07-19 20:02:55.000000000 +0300
52536 @@ -1,15 +1,26 @@
52537  #ifndef WIN32_SOCKET_H
52538  #define WIN32_SOCKET_H
52539  
52540 -#ifdef __WIN32
52541 +#ifdef _WIN32
52542  
52543  #include <winsock2.h>
52544  
52545  #define ECONNRESET WSAECONNRESET
52546  #define EINPROGRESS WSAEINPROGRESS
52547  #define EALREADY WSAEALREADY
52548 +#define ENOTCONN WSAENOTCONN
52549 +#define EWOULDBLOCK WSAEWOULDBLOCK
52550  #define ioctl ioctlsocket
52551  #define hstrerror(x) ""
52552 +#define STDIN_FILENO 0
52553 +#define STDOUT_FILENO 1
52554 +#define STDERR_FILENO 2
52555 +#define ssize_t int
52556 +
52557 +int inet_aton(const char *cp, struct in_addr *inp);
52558 +#define HAVE_INET_ADDR
52559 +#undef HAVE_INET_ATON
52560 +
52561  #else
52562  #include <sys/socket.h>
52563  #include <sys/ioctl.h>
52564 @@ -18,7 +29,29 @@
52565  #include <sys/un.h>
52566  #include <arpa/inet.h>
52567  
52568 +#ifndef SUN_LEN
52569 +#define SUN_LEN(su) \
52570 +        (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
52571 +#endif
52572 +
52573 +#define closesocket(x) close(x)
52574 +
52575  #include <netdb.h>
52576 +#endif /* !_WIN32 */
52577 +
52578 +#ifdef HAVE_INET_NTOP
52579 +# define HAVE_IPV6
52580 +#endif
52581 +
52582 +typedef union {
52583 +#ifdef HAVE_IPV6
52584 +       struct sockaddr_in6 ipv6;
52585 +#endif
52586 +       struct sockaddr_in ipv4;
52587 +#ifdef HAVE_SYS_UN_H
52588 +       struct sockaddr_un un;
52589  #endif
52590 +       struct sockaddr plain;
52591 +} sock_addr;
52592  
52593  #endif
52594 --- ../lighttpd-1.4.11/src/sys-strings.h        1970-01-01 03:00:00.000000000 +0300
52595 +++ lighttpd-1.4.12/src/sys-strings.h   2006-07-16 00:26:03.000000000 +0300
52596 @@ -0,0 +1,11 @@
52597 +#ifndef _SYS_STRINGS_H_
52598 +#define _SYS_STRINGS_H_
52599 +
52600 +#ifdef _WIN32
52601 +#define strcasecmp stricmp
52602 +#define strncasecmp strnicmp
52603 +#define strtoll(p, e, b) _strtoi64(p, e, b)
52604 +#endif
52605 +
52606 +#endif
52607 +
52608 --- ../lighttpd-1.4.11/tests/LightyTest.pm      2006-01-14 20:32:31.000000000 +0200
52609 +++ lighttpd-1.4.12/tests/LightyTest.pm 2006-07-18 13:03:40.000000000 +0300
52610 @@ -87,14 +87,16 @@
52611         # pre-process configfile if necessary
52612         #
52613  
52614 -       unlink($self->{TESTDIR}."/tmp/cfg.file");
52615 -       system("cat ".$self->{SRCDIR}."/".$self->{CONFIGFILE}.' | perl -pe "s#\@SRCDIR\@#'.$self->{BASEDIR}.'/tests/#" > '.$self->{TESTDIR}.'/tmp/cfg.file');
52616 +       $ENV{'SRCDIR'} = $self->{BASEDIR}.'/tests';
52617 +       $ENV{'PORT'} = $self->{PORT};
52618  
52619         unlink($self->{LIGHTTPD_PIDFILE});
52620 -       if (1) {
52621 -               system($self->{LIGHTTPD_PATH}." -f ".$self->{TESTDIR}."/tmp/cfg.file -m ".$self->{MODULES_PATH});
52622 +       if (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'strace') {
52623 +               system("strace -tt -s 512 -o strace ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &");
52624 +       } elsif (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'valgrind') {
52625 +               system("valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --logfile=valgrind ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &");
52626         } else {
52627 -               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}." &");
52628 +               system($self->{LIGHTTPD_PATH}." -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH});
52629         }
52630  
52631         select(undef, undef, undef, 0.1);
52632 @@ -184,7 +186,7 @@
52633                                         (my $h = $1) =~ tr/[A-Z]/[a-z]/;
52634  
52635                                         if (defined $resp_hdr{$h}) {
52636 -                                               diag(sprintf("header %s is duplicated: %s and %s\n",
52637 +                                               diag(sprintf("header '%s' is duplicated: '%s' and '%s'\n",
52638                                                              $h, $resp_hdr{$h}, $2));
52639                                         } else {
52640                                                 $resp_hdr{$h} = $2;
52641 @@ -196,6 +198,9 @@
52642                         }
52643                 }
52644  
52645 +               $t->{etag} = $resp_hdr{'etag'};
52646 +               $t->{date} = $resp_hdr{'date'};
52647 +
52648                 # check length
52649                 if (defined $resp_hdr{"content-length"}) {
52650                         $resp_body = substr($lines, 0, $resp_hdr{"content-length"});
52651 --- ../lighttpd-1.4.11/tests/Makefile.am        2005-09-16 15:48:40.000000000 +0300
52652 +++ lighttpd-1.4.12/tests/Makefile.am   2006-07-16 00:26:05.000000000 +0300
52653 @@ -39,10 +39,18 @@
52654        mod-redirect.t \
52655        mod-userdir.t \
52656        mod-rewrite.t \
52657 +      mod-proxy.t \
52658        request.t \
52659        mod-ssi.t \
52660        LightyTest.pm \
52661 -      mod-setenv.t 
52662 +      mod-setenv.t \
52663 +      lowercase.t \
52664 +      lowercase.conf \
52665 +      proxy.conf \
52666 +      cachable.t \
52667 +      default.conf \
52668 +      proxy-backend-1.conf \
52669 +      proxy-backend-2.conf 
52670  
52671  
52672  TESTS_ENVIRONMENT=$(srcdir)/wrapper.sh $(srcdir) $(top_builddir) 
52673 --- ../lighttpd-1.4.11/tests/bug-06.conf        2005-08-27 17:44:19.000000000 +0300
52674 +++ lighttpd-1.4.12/tests/bug-06.conf   2006-07-16 00:26:04.000000000 +0300
52675 @@ -1,5 +1,5 @@
52676 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52677 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52678 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52679 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52680  
52681  ## bind to port (default: 80)
52682  server.port                 = 2048
52683 @@ -8,7 +8,7 @@
52684  
52685  ## bind to localhost (default: all interfaces)
52686  server.bind                = "localhost"
52687 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52688 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52689  server.name                = "www.example.org"
52690  server.tag                 = "Apache 1.3.29"
52691  
52692 @@ -59,7 +59,7 @@
52693  ######################## MODULE CONFIG ############################
52694  
52695  
52696 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52697 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52698  
52699  mimetype.assign             = ( ".png"  => "image/png", 
52700                                  ".jpg"  => "image/jpeg",
52701 @@ -77,7 +77,7 @@
52702                                 ".c"    => "text/plain",
52703                                 ".conf" => "text/plain" )
52704  
52705 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52706 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52707  compress.filetype           = ("text/plain", "text/html")
52708  
52709  setenv.add-environment      = ( "TRAC_ENV" => "foo")
52710 @@ -90,7 +90,7 @@
52711                                     "host" => "127.0.0.1",
52712                                     "port" => 1026,
52713  #                                  "mode" => "authorizer",
52714 -#                                  "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
52715 +#                                  "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
52716                                   )
52717                                 )
52718                               )
52719 @@ -106,7 +106,7 @@
52720  ssl.pemfile                 = "server.pem"
52721  
52722  auth.backend                = "plain"
52723 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52724 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52725  auth.backend.plain.groupfile = "lighttpd.group"
52726  
52727  auth.backend.ldap.hostname  = "localhost"
52728 @@ -149,15 +149,15 @@
52729  status.config-url           = "/server-config"
52730  
52731  simple-vhost.document-root  = "pages"
52732 -simple-vhost.server-root    = "@SRCDIR@/tmp/lighttpd/servers/"
52733 +simple-vhost.server-root    = env.SRCDIR + "/tmp/lighttpd/servers/"
52734  simple-vhost.default-host   = "www.example.org"
52735  
52736  $HTTP["host"] == "vvv.example.org" {
52737 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52738 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52739  }
52740  
52741  $HTTP["host"] == "zzz.example.org" {
52742 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52743 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52744    server.name = "zzz.example.org"
52745  }
52746  
52747 --- ../lighttpd-1.4.11/tests/bug-12.conf        2005-08-27 17:44:19.000000000 +0300
52748 +++ lighttpd-1.4.12/tests/bug-12.conf   2006-07-16 00:26:04.000000000 +0300
52749 @@ -1,5 +1,5 @@
52750 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52751 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52752 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52753 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52754  
52755  ## bind to port (default: 80)
52756  server.port                 = 2048
52757 @@ -8,7 +8,7 @@
52758  
52759  ## bind to localhost (default: all interfaces)
52760  server.bind                = "localhost"
52761 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52762 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52763  server.name                = "www.example.org"
52764  server.tag                 = "Apache 1.3.29"
52765  
52766 @@ -61,7 +61,7 @@
52767  ######################## MODULE CONFIG ############################
52768  
52769  
52770 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52771 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52772  
52773  mimetype.assign             = ( ".png"  => "image/png", 
52774                                  ".jpg"  => "image/jpeg",
52775 @@ -79,7 +79,7 @@
52776                                 ".c"    => "text/plain",
52777                                 ".conf" => "text/plain" )
52778  
52779 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52780 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52781  compress.filetype           = ("text/plain", "text/html")
52782  
52783  setenv.add-environment      = ( "TRAC_ENV" => "foo")
52784 @@ -92,7 +92,7 @@
52785                                     "host" => "127.0.0.1",
52786                                     "port" => 1026,
52787  #                                  "mode" => "authorizer",
52788 -#                                  "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
52789 +#                                  "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
52790                                   )
52791                                 )
52792                               )
52793 @@ -108,7 +108,7 @@
52794  ssl.pemfile                 = "server.pem"
52795  
52796  auth.backend                = "plain"
52797 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52798 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52799  auth.backend.plain.groupfile = "lighttpd.group"
52800  
52801  auth.backend.ldap.hostname  = "localhost"
52802 @@ -151,15 +151,15 @@
52803  status.config-url           = "/server-config"
52804  
52805  simple-vhost.document-root  = "pages"
52806 -simple-vhost.server-root    = "@SRCDIR@/tmp/lighttpd/servers/"
52807 +simple-vhost.server-root    = env.SRCDIR + "/tmp/lighttpd/servers/"
52808  simple-vhost.default-host   = "www.example.org"
52809  
52810  $HTTP["host"] == "vvv.example.org" {
52811 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52812 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52813  }
52814  
52815  $HTTP["host"] == "zzz.example.org" {
52816 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52817 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52818    server.name = "zzz.example.org"
52819  }
52820  
52821 --- ../lighttpd-1.4.11/tests/cachable.t 1970-01-01 03:00:00.000000000 +0300
52822 +++ lighttpd-1.4.12/tests/cachable.t    2006-07-18 13:03:40.000000000 +0300
52823 @@ -0,0 +1,112 @@
52824 +#!/usr/bin/env perl
52825 +BEGIN {
52826 +    # add current source dir to the include-path
52827 +    # we need this for make distcheck
52828 +   (my $srcdir = $0) =~ s#/[^/]+$#/#;
52829 +   unshift @INC, $srcdir;
52830 +}
52831 +
52832 +use strict;
52833 +use IO::Socket;
52834 +use Test::More tests => 12;
52835 +use LightyTest;
52836 +
52837 +my $tf = LightyTest->new();
52838 +my $t;
52839 +
52840 +$tf->{CONFIGFILE} = 'lighttpd.conf';
52841 +    
52842 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
52843 +
52844 +## check if If-Modified-Since, If-None-Match works
52845 +
52846 +$t->{REQUEST}  = ( <<EOF
52847 +GET / HTTP/1.0
52848 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT
52849 +EOF
52850 + );
52851 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52852 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since');
52853 +
52854 +$t->{REQUEST}  = ( <<EOF
52855 +GET / HTTP/1.0
52856 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52857 +EOF
52858 + );
52859 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Last-Modified' => ''} ];
52860 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since, comment');
52861 +
52862 +my $now = $t->{date};
52863 +
52864 +$t->{REQUEST}  = ( <<EOF
52865 +GET / HTTP/1.0
52866 +If-Modified-Since: $now
52867 +EOF
52868 + );
52869 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52870 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since');
52871 +
52872 +$t->{REQUEST}  = ( <<EOF
52873 +GET / HTTP/1.0
52874 +If-Modified-Since: $now; foo
52875 +EOF
52876 + );
52877 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52878 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since, comment');
52879 +
52880 +$t->{REQUEST}  = ( <<EOF
52881 +GET / HTTP/1.0
52882 +If-None-Match: foo
52883 +EOF
52884 + );
52885 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+ETag' => ''} ];
52886 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
52887 +
52888 +my $etag = $t->{etag};
52889 +
52890 +$t->{REQUEST}  = ( <<EOF
52891 +GET / HTTP/1.0
52892 +If-None-Match: $etag
52893 +EOF
52894 + );
52895 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52896 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
52897 +
52898 +$t->{REQUEST}  = ( <<EOF
52899 +GET / HTTP/1.0
52900 +If-None-Match: $etag
52901 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52902 +EOF
52903 + );
52904 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52905 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + old Last-Modified');
52906 +
52907 +$t->{REQUEST}  = ( <<EOF
52908 +GET / HTTP/1.0
52909 +If-None-Match: $etag
52910 +If-Modified-Since: $now; foo
52911 +EOF
52912 + );
52913 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52914 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag, Last-Modified + comment');
52915 +
52916 +$t->{REQUEST}  = ( <<EOF
52917 +GET / HTTP/1.0
52918 +If-None-Match: Foo
52919 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52920 +EOF
52921 + );
52922 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52923 +ok($tf->handle_http($t) == 0, 'Conditional GET - old ETAG + old Last-Modified');
52924 +
52925 +$t->{REQUEST}  = ( <<EOF
52926 +GET / HTTP/1.0
52927 +If-None-Match: $etag
52928 +If-Modified-Since: $now foo
52929 +EOF
52930 + );
52931 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 412 } ];
52932 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + Last-Modified + overlong timestamp');
52933 +
52934 +ok($tf->stop_proc == 0, "Stopping lighttpd");
52935 +
52936 --- ../lighttpd-1.4.11/tests/condition.conf     2005-08-27 17:44:19.000000000 +0300
52937 +++ lighttpd-1.4.12/tests/condition.conf        2006-07-16 00:26:05.000000000 +0300
52938 @@ -2,15 +2,15 @@
52939  debug.log-request-handling = "enable"
52940  debug.log-condition-handling = "enable"
52941  
52942 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52943 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52944 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52945 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52946  
52947  ## bind to port (default: 80)
52948  server.port                 = 2048
52949  
52950  ## bind to localhost (default: all interfaces)
52951  server.bind                = "localhost"
52952 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52953 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52954  server.name                = "www.example.org"
52955  server.tag                 = "Apache 1.3.29"
52956  
52957 @@ -22,25 +22,25 @@
52958  ######################## MODULE CONFIG ############################
52959  
52960  
52961 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52962 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52963  
52964  mimetype.assign             = ( ".html" => "text/html" )
52965  
52966  url.redirect = ("^" => "/default")
52967  
52968  $HTTP["host"] == "www.example.org" {
52969 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52970 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52971    server.name = "www.example.org"
52972    url.redirect = ("^" => "/match_1")
52973  }
52974  else $HTTP["host"] == "test1.example.org" {
52975 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52976 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52977    server.name = "test1.example.org"
52978    url.redirect = ("^" => "/match_2")
52979  }
52980  # comments
52981  else $HTTP["host"] == "test2.example.org" {
52982 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52983 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52984    server.name = "test2.example.org"
52985    url.redirect = ("^" => "/match_3")
52986  }
52987 @@ -48,7 +48,7 @@
52988          # comments
52989  
52990  else $HTTP["host"] == "test3.example.org" {
52991 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52992 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52993    server.name = "test3.example.org"
52994    url.redirect = ("^" => "/match_4")
52995  
52996 --- ../lighttpd-1.4.11/tests/core-keepalive.t   2005-11-17 15:54:19.000000000 +0200
52997 +++ lighttpd-1.4.12/tests/core-keepalive.t      2006-07-16 00:26:05.000000000 +0300
52998 @@ -40,7 +40,7 @@
52999  
53000  GET /12345.txt HTTP/1.0
53001  Host: 123.example.org
53002 -Connection: keep-alive
53003 +Connection: close
53004  EOF
53005   );
53006  $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } , { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53007 --- ../lighttpd-1.4.11/tests/default.conf       1970-01-01 03:00:00.000000000 +0300
53008 +++ lighttpd-1.4.12/tests/default.conf  2006-07-16 00:26:05.000000000 +0300
53009 @@ -0,0 +1,111 @@
53010 +server.name                = "www.example.org"
53011 +
53012 +## bind to port (default: 80)
53013 +server.port                 = env.PORT
53014 +
53015 +
53016 +server.dir-listing          = "enable"
53017 +
53018 +#server.event-handler        = "linux-sysepoll"
53019 +#server.event-handler        = "linux-rtsig"
53020 +
53021 +server.modules              = ( 
53022 +                               "mod_rewrite",
53023 +                               "mod_setenv",
53024 +                               "mod_access", 
53025 +                               "mod_auth",
53026 +                               "mod_status", 
53027 +                               "mod_expire",
53028 +                               "mod_simple_vhost",
53029 +                               "mod_redirect", 
53030 +                               "mod_secdownload",
53031 +                               "mod_ssi",
53032 +                               "mod_fastcgi",
53033 +                               "mod_proxy",
53034 +                               "mod_cgi",
53035 +                               "mod_compress",
53036 +                               "mod_userdir",
53037 +                               "mod_accesslog" ) 
53038 +
53039 +server.indexfiles           = ( "index.php", "index.html", 
53040 +                                "index.htm", "default.htm" )
53041 +
53042 +ssi.extension = ( ".shtml" )
53043 +
53044 +######################## MODULE CONFIG ############################
53045 +
53046 +
53047 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53048 +server.errorlog             = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53049 +
53050 +mimetype.assign             = ( ".png"  => "image/png", 
53051 +                                ".jpg"  => "image/jpeg",
53052 +                                ".jpeg" => "image/jpeg",
53053 +                                ".gif"  => "image/gif",
53054 +                                ".html" => "text/html",
53055 +                                ".htm"  => "text/html",
53056 +                                ".pdf"  => "application/pdf",
53057 +                                ".swf"  => "application/x-shockwave-flash",
53058 +                                ".spl"  => "application/futuresplash",
53059 +                                ".txt"  => "text/plain",
53060 +                                ".tar.gz" =>   "application/x-tgz",
53061 +                                ".tgz"  => "application/x-tgz",
53062 +                                ".gz"   => "application/x-gzip",
53063 +                               ".c"    => "text/plain",
53064 +                               ".conf" => "text/plain" )
53065 +
53066 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53067 +compress.filetype           = ("text/plain", "text/html")
53068 +
53069 +setenv.add-environment      = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
53070 +
53071 +cgi.assign                  = ( ".pl"  => "/usr/bin/perl",
53072 +                                ".cgi" => "/usr/bin/perl",
53073 +                               ".py"  => "/usr/bin/python" )
53074 +                       
53075 +userdir.include-user = ( "jan" )
53076 +userdir.path = "/"
53077 +
53078 +ssl.engine                  = "disable"
53079 +ssl.pemfile                 = "server.pem"
53080 +
53081 +auth.backend                = "plain"
53082 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53083 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
53084 +auth.backend.plain.groupfile = "lighttpd.group"
53085 +
53086 +auth.backend.ldap.hostname  = "localhost"
53087 +auth.backend.ldap.base-dn   = "dc=my-domain,dc=com"
53088 +auth.backend.ldap.filter    = "(uid=$)"
53089 +
53090 +auth.require                = ( "/server-status" => 
53091 +                                ( 
53092 +                                 "method"  => "digest",
53093 +                                 "realm"   => "download archiv",
53094 +                                 "require" => "valid-user"
53095 +                               ),
53096 +                               "/auth.php" => 
53097 +                                ( 
53098 +                                 "method"  => "basic",
53099 +                                 "realm"   => "download archiv",
53100 +                                 "require" => "user=jan"
53101 +                               ),
53102 +                               "/server-config" => 
53103 +                                ( 
53104 +                                 "method"  => "basic",
53105 +                                 "realm"   => "download archiv",
53106 +                                 "require" => "valid-user"
53107 +                               )
53108 +                              )
53109 +
53110 +url.access-deny             = ( "~", ".inc")
53111 +
53112 +url.redirect                = ( "^/redirect/$" => "http://localhost:2048/" )
53113 +
53114 +url.rewrite                = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
53115 +                               "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
53116 +
53117 +#### status module
53118 +status.status-url           = "/server-status"
53119 +status.config-url           = "/server-config"
53120 +
53121 --- ../lighttpd-1.4.11/tests/docroot/www/dummydir/.svn/entries  2006-03-09 19:21:49.000000000 +0200
53122 +++ lighttpd-1.4.12/tests/docroot/www/dummydir/.svn/entries     2006-07-20 00:57:20.000000000 +0300
53123 @@ -9,5 +9,6 @@
53124     last-author="jan"
53125     kind="dir"
53126     uuid="152afb58-edef-0310-8abb-c4023f1b3aa9"
53127 -   revision="1040"/>
53128 +   repos="svn://svn.lighttpd.net/lighttpd"
53129 +   revision="1210"/>
53130  </wc-entries>
53131 --- ../lighttpd-1.4.11/tests/fastcgi-10.conf    2005-08-31 23:36:34.000000000 +0300
53132 +++ lighttpd-1.4.12/tests/fastcgi-10.conf       2006-07-16 00:26:04.000000000 +0300
53133 @@ -1,12 +1,12 @@
53134 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53135 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53136 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53137 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53138  
53139  ## bind to port (default: 80)
53140  server.port                 = 2048
53141  
53142  ## bind to localhost (default: all interfaces)
53143  server.bind                = "localhost"
53144 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53145 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53146  server.name                = "www.example.org"
53147  server.tag                 = "Apache 1.3.29"
53148  
53149 @@ -44,7 +44,7 @@
53150  ######################## MODULE CONFIG ############################
53151  
53152  
53153 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53154 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53155  
53156  mimetype.assign             = ( ".png"  => "image/png", 
53157                                  ".jpg"  => "image/jpeg",
53158 @@ -62,7 +62,7 @@
53159                                 ".c"    => "text/plain",
53160                                 ".conf" => "text/plain" )
53161  
53162 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53163 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53164  compress.filetype           = ("text/plain", "text/html")
53165  
53166  fastcgi.debug               = 0
53167 @@ -85,7 +85,7 @@
53168  ssl.pemfile                 = "server.pem"
53169  
53170  auth.backend                = "plain"
53171 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53172 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53173  auth.backend.plain.groupfile = "lighttpd.group"
53174  
53175  auth.backend.ldap.hostname  = "localhost"
53176 @@ -128,11 +128,11 @@
53177  status.config-url           = "/server-config"
53178  
53179  $HTTP["host"] == "vvv.example.org" {
53180 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53181 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53182  }
53183  
53184  $HTTP["host"] == "zzz.example.org" {
53185 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53186 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53187    server.name = "zzz.example.org"
53188  }
53189  
53190 --- ../lighttpd-1.4.11/tests/fastcgi-13.conf    2006-01-03 12:38:17.000000000 +0200
53191 +++ lighttpd-1.4.12/tests/fastcgi-13.conf       2006-07-18 13:03:40.000000000 +0300
53192 @@ -1,5 +1,5 @@
53193 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53194 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53195 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53196 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53197  
53198  debug.log-request-header   = "enable"
53199  debug.log-response-header  = "enable"
53200 @@ -10,7 +10,7 @@
53201  
53202  ## bind to localhost (default: all interfaces)
53203  server.bind                = "localhost"
53204 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53205 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53206  server.name                = "www.example.org"
53207  server.tag                 = "Apache 1.3.29"
53208  
53209 @@ -59,7 +59,7 @@
53210  ######################## MODULE CONFIG ############################
53211  
53212  
53213 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53214 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53215  
53216  mimetype.assign             = ( ".png"  => "image/png", 
53217                                  ".jpg"  => "image/jpeg",
53218 @@ -77,7 +77,7 @@
53219                                 ".c"    => "text/plain",
53220                                 ".conf" => "text/plain" )
53221  
53222 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53223 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53224  compress.filetype           = ("text/plain", "text/html")
53225  
53226  fastcgi.debug               = 0
53227 @@ -85,7 +85,7 @@
53228                                    "grisu" => ( 
53229                                     "host" => "127.0.0.1",
53230                                     "port" => 1048,
53231 -                                   "bin-path" => "/home/jan/Documents/php-5.1.0/sapi/cgi/php -c /usr/local/lib/php.ini",
53232 +                                   "bin-path" => "/home/jan/Documents/php-5.1.4/sapi/cgi/php -c /usr/local/lib/php.ini",
53233                                     "bin-copy-environment" => ( "PATH", "SHELL", "USER" ),
53234                                   )
53235                                 )
53236 @@ -102,7 +102,7 @@
53237  ssl.pemfile                 = "server.pem"
53238  
53239  auth.backend                = "plain"
53240 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53241 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53242  auth.backend.plain.groupfile = "lighttpd.group"
53243  
53244  auth.backend.ldap.hostname  = "localhost"
53245 @@ -145,11 +145,11 @@
53246  status.config-url           = "/server-config"
53247  
53248  $HTTP["host"] == "vvv.example.org" {
53249 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53250 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53251  }
53252  
53253  $HTTP["host"] == "zzz.example.org" {
53254 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53255 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53256    server.name = "zzz.example.org"
53257  }
53258  
53259 --- ../lighttpd-1.4.11/tests/fastcgi-auth.conf  2005-08-27 17:44:19.000000000 +0300
53260 +++ lighttpd-1.4.12/tests/fastcgi-auth.conf     2006-07-16 00:26:05.000000000 +0300
53261 @@ -1,5 +1,5 @@
53262 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53263 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53264 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53265 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53266  
53267  debug.log-request-header   = "enable"
53268  debug.log-response-header  = "enable"
53269 @@ -12,7 +12,7 @@
53270  
53271  ## bind to localhost (default: all interfaces)
53272  server.bind                = "localhost"
53273 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53274 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53275  server.name                = "www.example.org"
53276  server.tag                 = "Apache 1.3.29"
53277  
53278 @@ -61,7 +61,7 @@
53279  ######################## MODULE CONFIG ############################
53280  
53281  
53282 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53283 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53284  
53285  mimetype.assign             = ( ".png"  => "image/png", 
53286                                  ".jpg"  => "image/jpeg",
53287 @@ -79,7 +79,7 @@
53288                                 ".c"    => "text/plain",
53289                                 ".conf" => "text/plain" )
53290  
53291 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53292 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53293  compress.filetype           = ("text/plain", "text/html")
53294  
53295  fastcgi.debug               = 0
53296 @@ -87,9 +87,9 @@
53297                                    "grisu" => ( 
53298                                     "host" => "127.0.0.1",
53299                                     "port" => 20000,
53300 -                                   "bin-path" => "@SRCDIR@/fcgi-auth",
53301 +                                   "bin-path" => env.SRCDIR + "/fcgi-auth",
53302                                      "mode" => "authorizer",
53303 -                                    "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
53304 +                                    "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
53305                                     
53306                                   )
53307                                 )
53308 @@ -106,7 +106,7 @@
53309  ssl.pemfile                 = "server.pem"
53310  
53311  auth.backend                = "plain"
53312 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53313 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53314  auth.backend.plain.groupfile = "lighttpd.group"
53315  
53316  auth.backend.ldap.hostname  = "localhost"
53317 @@ -149,11 +149,11 @@
53318  status.config-url           = "/server-config"
53319  
53320  $HTTP["host"] == "vvv.example.org" {
53321 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53322 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53323  }
53324  
53325  $HTTP["host"] == "zzz.example.org" {
53326 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53327 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53328    server.name = "zzz.example.org"
53329  }
53330  
53331 --- ../lighttpd-1.4.11/tests/fastcgi-responder.conf     2005-08-27 17:44:19.000000000 +0300
53332 +++ lighttpd-1.4.12/tests/fastcgi-responder.conf        2006-07-16 00:26:05.000000000 +0300
53333 @@ -1,5 +1,5 @@
53334 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53335 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53336 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53337 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53338  
53339  #debug.log-request-header   = "enable"
53340  #debug.log-response-header  = "enable"
53341 @@ -15,7 +15,7 @@
53342  
53343  ## bind to localhost (default: all interfaces)
53344  server.bind                = "localhost"
53345 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53346 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53347  server.name                = "www.example.org"
53348  server.tag                 = "Apache 1.3.29"
53349  
53350 @@ -64,7 +64,7 @@
53351  ######################## MODULE CONFIG ############################
53352  
53353  
53354 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53355 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53356  
53357  mimetype.assign             = ( ".png"  => "image/png", 
53358                                  ".jpg"  => "image/jpeg",
53359 @@ -82,7 +82,7 @@
53360                                 ".c"    => "text/plain",
53361                                 ".conf" => "text/plain" )
53362  
53363 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53364 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53365  compress.filetype           = ("text/plain", "text/html")
53366  
53367  fastcgi.debug               = 0
53368 @@ -90,10 +90,11 @@
53369                                    "grisu" => ( 
53370                                     "host" => "127.0.0.1",
53371                                     "port" => 10000,
53372 -                                   "bin-path" => "@SRCDIR@/fcgi-responder",
53373 +                                   "bin-path" => env.SRCDIR + "/fcgi-responder",
53374                                     "check-local" => "disable",
53375                                     "max-procs" => 1,
53376 -                                   "min-procs" => 1
53377 +                                   "min-procs" => 1,
53378 +                                   "allow-x-send-file" => "enable",
53379                                   )
53380                                 )
53381                               )
53382 @@ -109,7 +110,7 @@
53383  ssl.pemfile                 = "server.pem"
53384  
53385  auth.backend                = "plain"
53386 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53387 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53388  auth.backend.plain.groupfile = "lighttpd.group"
53389  
53390  auth.backend.ldap.hostname  = "localhost"
53391 @@ -152,11 +153,11 @@
53392  status.config-url           = "/server-config"
53393  
53394  $HTTP["host"] == "vvv.example.org" {
53395 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53396 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53397  }
53398  
53399  $HTTP["host"] == "zzz.example.org" {
53400 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53401 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53402    server.name = "zzz.example.org"
53403  }
53404  
53405 --- ../lighttpd-1.4.11/tests/fcgi-responder.c   2005-08-11 01:26:55.000000000 +0300
53406 +++ lighttpd-1.4.12/tests/fcgi-responder.c      2006-07-16 00:26:05.000000000 +0300
53407 @@ -6,11 +6,17 @@
53408  int main () {
53409         int num_requests = 2;
53410         
53411 -       while (num_requests > 0 &&
53412 -              FCGI_Accept() >= 0) {
53413 -               char* p;
53414 -               
53415 -               if (NULL != (p = getenv("QUERY_STRING"))) {
53416 +       while (num_requests > 0 && FCGI_Accept() >= 0) {
53417 +               char* p = NULL;
53418 +               char* doc_root = NULL;
53419 +               char fname[4096];
53420 +               char* pfname = (char *)fname;
53421 +
53422 +               doc_root = getenv("DOCUMENT_ROOT");
53423 +               p = getenv("QUERY_STRING");
53424 +
53425 +               if (NULL != p && NULL != doc_root) {
53426 +                       snprintf(pfname, sizeof(fname), "%s/phpinfo.php", doc_root);
53427                         if (0 == strcmp(p, "lf")) {
53428                                 printf("Status: 200 OK\n\n");
53429                         } else if (0 == strcmp(p, "crlf")) {
53430 @@ -23,6 +29,18 @@
53431                                 printf("Status: 200 OK\r\n");
53432                                 fflush(stdout);
53433                                 printf("\r\n");
53434 +                       } else if (0 == strcmp(p,"x-lighttpd-send-file")) {
53435 +                               printf("Status: 200 OK\r\n");
53436 +                               printf("X-LIGHTTPD-send-file: %s\r\n", pfname);
53437 +                               printf("\r\n");
53438 +                       } else if (0 == strcmp(p,"xsendfile")) {
53439 +                               printf("Status: 200 OK\r\n");
53440 +                               printf("X-Sendfile: %s\r\n", pfname);
53441 +                               printf("\r\n");
53442 +                       } else if (0 == strcmp(p,"xsendfile-mixed-case")) {
53443 +                               printf("Status: 200 OK\r\n");
53444 +                               printf("X-SeNdFiLe: %s\r\n", pfname);
53445 +                               printf("\r\n");
53446                         } else if (0 == strcmp(p, "die-at-end")) {
53447                                 printf("Status: 200 OK\r\n\r\n");
53448                                 num_requests--;
53449 --- ../lighttpd-1.4.11/tests/lighttpd.conf      2006-03-09 15:26:58.000000000 +0200
53450 +++ lighttpd-1.4.12/tests/lighttpd.conf 2006-07-16 00:26:05.000000000 +0300
53451 @@ -1,80 +1,18 @@
53452 -debug.log-request-handling = "enable"
53453 -debug.log-condition-handling = "enable"
53454 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53455 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53456 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53457 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53458 +server.tag = "Apache 1.3.29"
53459  
53460  ## 64 Mbyte ... nice limit
53461  server.max-request-size = 65000
53462  
53463 -## bind to port (default: 80)
53464 -server.port                 = 2048
53465 +include "default.conf"
53466  
53467 -## bind to localhost (default: all interfaces)
53468 -server.bind                = "localhost"
53469 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53470 -server.name                = "www.example.org"
53471 -server.tag                 = "Apache 1.3.29"
53472 -
53473 -server.dir-listing          = "enable"
53474 -
53475 -#server.event-handler        = "linux-sysepoll"
53476 -#server.event-handler        = "linux-rtsig"
53477 -
53478 -#server.modules.path         = ""
53479 -server.modules              = ( 
53480 -                               "mod_rewrite",
53481 -                               "mod_setenv",
53482 -                               "mod_secdownload",
53483 -                               "mod_access", 
53484 -                               "mod_auth",
53485 -#                              "mod_httptls",
53486 -                               "mod_status", 
53487 -                               "mod_expire",
53488 -                               "mod_simple_vhost",
53489 -                               "mod_redirect", 
53490 -#                              "mod_evhost",
53491 -#                              "mod_localizer",
53492 -                               "mod_fastcgi",
53493 -                               "mod_cgi",
53494 -                               "mod_compress",
53495 -                               "mod_userdir",
53496 -                               "mod_ssi",
53497 -                               "mod_accesslog" ) 
53498 -
53499 -server.indexfiles           = ( "index.php", "index.html", 
53500 -                                "index.htm", "default.htm" )
53501 -
53502 -
53503 -######################## MODULE CONFIG ############################
53504 -
53505 -ssi.extension = ( ".shtml" )
53506 -
53507 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53508 -
53509 -mimetype.assign             = ( ".png"  => "image/png", 
53510 -                                ".jpg"  => "image/jpeg",
53511 -                                ".jpeg" => "image/jpeg",
53512 -                                ".gif"  => "image/gif",
53513 -                                ".html" => "text/html",
53514 -                                ".htm"  => "text/html",
53515 -                                ".pdf"  => "application/pdf",
53516 -                                ".swf"  => "application/x-shockwave-flash",
53517 -                                ".spl"  => "application/futuresplash",
53518 -                                ".txt"  => "text/plain",
53519 -                                ".tar.gz" =>   "application/x-tgz",
53520 -                                ".tgz"  => "application/x-tgz",
53521 -                                ".gz"   => "application/x-gzip",
53522 -                               ".c"    => "text/plain",
53523 -                               ".conf" => "text/plain" )
53524 +setenv.add-request-header   = ( "FOO" => "foo")
53525 +setenv.add-response-header  = ( "BAR" => "foo")
53526  
53527  $HTTP["host"] == "cache.example.org" {
53528 -  compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53529 +  compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53530  }
53531 -compress.filetype           = ("text/plain", "text/html")
53532 -
53533 -setenv.add-environment      = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
53534 -setenv.add-request-header   = ( "FOO" => "foo")
53535 -setenv.add-response-header  = ( "BAR" => "foo")
53536  
53537  $HTTP["url"] =~ "\.pdf$" {
53538    server.range-requests = "disable"
53539 @@ -85,76 +23,31 @@
53540                                 "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
53541                               )
53542                 
53543 -
53544 -cgi.assign                  = ( ".pl"  => "/usr/bin/perl",
53545 -                                ".cgi" => "/usr/bin/perl",
53546 -                               ".py"  => "/usr/bin/python" )
53547 -                       
53548 -userdir.include-user = ( "jan" )
53549 -userdir.path = "/"
53550 -
53551 -ssl.engine                  = "disable"
53552 -ssl.pemfile                 = "server.pem"
53553 -
53554  $HTTP["host"] == "auth-htpasswd.example.org" {
53555         auth.backend                = "htpasswd"
53556  }
53557  
53558 -auth.backend                = "plain"
53559 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53560 -
53561 -auth.backend.htpasswd.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.htpasswd"
53562 -
53563 -
53564 -auth.require                = ( "/server-status" => 
53565 -                                ( 
53566 -                                 "method"  => "digest",
53567 -                                 "realm"   => "download archiv",
53568 -                                 "require" => "group=www|user=jan|host=192.168.2.10"
53569 -                               ),
53570 -                               "/server-config" => 
53571 -                                ( 
53572 -                                 "method"  => "basic",
53573 -                                 "realm"   => "download archiv",
53574 -                                 "require" => "valid-user"
53575 -                               )
53576 -                              )
53577 -
53578 -url.access-deny             = ( "~", ".inc")
53579 -
53580 -url.rewrite                = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
53581 -                               "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
53582 -
53583 -expire.url                  = ( "/expire/access" => "access 2 hours", 
53584 -                               "/expire/modification" => "access plus 1 seconds 2 minutes")
53585 -
53586 -#cache.cache-dir             = "/home/weigon/wwwroot/cache/"
53587 -
53588 -#### status module
53589 -status.status-url           = "/server-status"
53590 -status.config-url           = "/server-config"
53591 -
53592  $HTTP["host"] == "vvv.example.org" {
53593 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53594 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53595    secdownload.secret          = "verysecret"
53596 -  secdownload.document-root   = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53597 +  secdownload.document-root   = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53598    secdownload.uri-prefix      = "/sec/"
53599    secdownload.timeout         = 120
53600  }
53601  
53602  $HTTP["host"] == "zzz.example.org" {
53603 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53604 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53605    server.name = "zzz.example.org"
53606  }
53607  
53608  $HTTP["host"] == "no-simple.example.org" {
53609 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/123.example.org/pages/"
53610 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/123.example.org/pages/"
53611    server.name = "zzz.example.org"
53612  }
53613  
53614  $HTTP["host"] !~ "(no-simple\.example\.org)" {
53615    simple-vhost.document-root  = "pages"
53616 -  simple-vhost.server-root    = "@SRCDIR@/tmp/lighttpd/servers/"
53617 +  simple-vhost.server-root    = env.SRCDIR + "/tmp/lighttpd/servers/"
53618    simple-vhost.default-host   = "www.example.org"
53619  }
53620  
53621 --- ../lighttpd-1.4.11/tests/lowercase.conf     1970-01-01 03:00:00.000000000 +0300
53622 +++ lighttpd-1.4.12/tests/lowercase.conf        2006-07-16 00:26:05.000000000 +0300
53623 @@ -0,0 +1,80 @@
53624 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53625 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53626 +
53627 +## bind to port (default: 80)
53628 +server.port                 = 2048
53629 +
53630 +## bind to localhost (default: all interfaces)
53631 +server.bind                = "localhost"
53632 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53633 +
53634 +server.force-lowercase-filenames = "enable"
53635 +
53636 +server.dir-listing          = "enable"
53637 +
53638 +server.modules              = ( 
53639 +                               "mod_rewrite",
53640 +                               "mod_setenv",
53641 +                               "mod_secdownload",
53642 +                               "mod_access", 
53643 +                               "mod_auth",
53644 +                               "mod_status", 
53645 +                               "mod_expire",
53646 +                               "mod_redirect", 
53647 +                               "mod_fastcgi",
53648 +                               "mod_cgi" ) 
53649 +
53650 +server.indexfiles           = ( "index.php", "index.html", 
53651 +                                "index.htm", "default.htm" )
53652 +
53653 +
53654 +######################## MODULE CONFIG ############################
53655 +
53656 +mimetype.assign             = ( ".png"  => "image/png", 
53657 +                                ".jpg"  => "image/jpeg",
53658 +                                ".jpeg" => "image/jpeg",
53659 +                                ".gif"  => "image/gif",
53660 +                                ".html" => "text/html",
53661 +                                ".htm"  => "text/html",
53662 +                                ".pdf"  => "application/pdf",
53663 +                                ".swf"  => "application/x-shockwave-flash",
53664 +                                ".spl"  => "application/futuresplash",
53665 +                                ".txt"  => "text/plain",
53666 +                                ".tar.gz" =>   "application/x-tgz",
53667 +                                ".tgz"  => "application/x-tgz",
53668 +                                ".gz"   => "application/x-gzip",
53669 +                               ".c"    => "text/plain",
53670 +                               ".conf" => "text/plain" )
53671 +
53672 +fastcgi.debug               = 0
53673 +fastcgi.server              = ( ".php" =>        ( ( "host" => "127.0.0.1", "port" => 1026, "broken-scriptfilename" => "enable" ) ),
53674 +                               "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
53675 +                             )
53676 +               
53677 +
53678 +cgi.assign                  = ( ".pl"  => "/usr/bin/perl",
53679 +                                ".cgi" => "/usr/bin/perl",
53680 +                               ".py"  => "/usr/bin/python" )
53681 +                       
53682 +auth.backend                = "plain"
53683 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53684 +
53685 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
53686 +
53687 +$HTTP["host"] == "lowercase-auth" {
53688 +  auth.require             = ( "/image.jpg" => 
53689 +                                ( 
53690 +                                 "method"  => "digest",
53691 +                                 "realm"   => "download archiv",
53692 +                                 "require" => "valid-user"
53693 +                               )
53694 +                              )
53695 +}
53696 +
53697 +$HTTP["host"] == "lowercase-deny" {
53698 +  url.access-deny             = ( ".jpg")
53699 +}
53700 +
53701 +$HTTP["host"] == "lowercase-exclude" {
53702 +  static-file.exclude-extensions = ( ".jpg" )
53703 +}
53704 --- ../lighttpd-1.4.11/tests/lowercase.t        1970-01-01 03:00:00.000000000 +0300
53705 +++ lighttpd-1.4.12/tests/lowercase.t   2006-07-16 00:26:05.000000000 +0300
53706 @@ -0,0 +1,94 @@
53707 +#!/usr/bin/env perl
53708 +BEGIN {
53709 +    # add current source dir to the include-path
53710 +    # we need this for make distcheck
53711 +   (my $srcdir = $0) =~ s#/[^/]+$#/#;
53712 +   unshift @INC, $srcdir;
53713 +}
53714 +
53715 +use strict;
53716 +use IO::Socket;
53717 +use Test::More tests => 10;
53718 +use LightyTest;
53719 +
53720 +my $tf = LightyTest->new();
53721 +my $t;
53722 +
53723 +$tf->{CONFIGFILE} = 'lowercase.conf';
53724 +    
53725 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
53726 +
53727 +## check if lower-casing works
53728 +
53729 +$t->{REQUEST}  = ( <<EOF
53730 +GET /image.JPG HTTP/1.0
53731 +EOF
53732 + );
53733 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53734 +ok($tf->handle_http($t) == 0, 'uppercase access');
53735 +
53736 +$t->{REQUEST}  = ( <<EOF
53737 +GET /image.jpg HTTP/1.0
53738 +EOF
53739 + );
53740 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53741 +ok($tf->handle_http($t) == 0, 'lowercase access');
53742 +
53743 +## check that mod-auth works
53744 +
53745 +$t->{REQUEST}  = ( <<EOF
53746 +GET /image.JPG HTTP/1.0
53747 +Host: lowercase-auth
53748 +EOF
53749 + );
53750 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
53751 +ok($tf->handle_http($t) == 0, 'uppercase access');
53752 +
53753 +$t->{REQUEST}  = ( <<EOF
53754 +GET /image.jpg HTTP/1.0
53755 +Host: lowercase-auth
53756 +EOF
53757 + );
53758 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
53759 +ok($tf->handle_http($t) == 0, 'lowercase access');
53760 +
53761 +
53762 +## check that mod-staticfile exclude works
53763 +$t->{REQUEST}  = ( <<EOF
53764 +GET /image.JPG HTTP/1.0
53765 +Host: lowercase-exclude
53766 +EOF
53767 + );
53768 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53769 +ok($tf->handle_http($t) == 0, 'upper case access to staticfile.exclude-extension');
53770 +
53771 +$t->{REQUEST}  = ( <<EOF
53772 +GET /image.jpg HTTP/1.0
53773 +Host: lowercase-exclude
53774 +EOF
53775 + );
53776 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53777 +ok($tf->handle_http($t) == 0, 'lowercase access');
53778 +
53779 +
53780 +## check that mod-access exclude works
53781 +$t->{REQUEST}  = ( <<EOF
53782 +GET /image.JPG HTTP/1.0
53783 +Host: lowercase-deny
53784 +EOF
53785 + );
53786 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53787 +ok($tf->handle_http($t) == 0, 'uppercase access to url.access-deny protected location');
53788 +
53789 +$t->{REQUEST}  = ( <<EOF
53790 +GET /image.jpg HTTP/1.0
53791 +Host: lowercase-deny
53792 +EOF
53793 + );
53794 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53795 +ok($tf->handle_http($t) == 0, 'lowercase access');
53796 +
53797 +
53798 +
53799 +ok($tf->stop_proc == 0, "Stopping lighttpd");
53800 +
53801 --- ../lighttpd-1.4.11/tests/mod-cgi.t  2005-09-01 14:43:05.000000000 +0300
53802 +++ lighttpd-1.4.12/tests/mod-cgi.t     2006-07-18 13:03:40.000000000 +0300
53803 @@ -43,7 +43,7 @@
53804  GET /nph-status.pl HTTP/1.0
53805  EOF
53806   );
53807 -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53808 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 502 } ];
53809  ok($tf->handle_http($t) == 0, 'NPH + perl, Bug #14');
53810  
53811  $t->{REQUEST} = ( <<EOF
53812 --- ../lighttpd-1.4.11/tests/mod-fastcgi.t      2006-03-09 15:30:45.000000000 +0200
53813 +++ lighttpd-1.4.12/tests/mod-fastcgi.t 2006-07-18 13:03:40.000000000 +0300
53814 @@ -7,7 +7,7 @@
53815  }
53816  
53817  use strict;
53818 -use Test::More tests => 47;
53819 +use Test::More tests => 49;
53820  use LightyTest;
53821  
53822  my $tf = LightyTest->new();
53823 @@ -15,7 +15,7 @@
53824  my $t;
53825  
53826  SKIP: {
53827 -       skip "no PHP running on port 1026", 30 unless $tf->listening_on(1026);
53828 +       skip "no PHP running on port 1026", 29 unless $tf->listening_on(1026);
53829  
53830         ok($tf->start_proc == 0, "Starting lighttpd") or die();
53831  
53832 @@ -223,7 +223,7 @@
53833  }
53834  
53835  SKIP: {
53836 -       skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.0/sapi/cgi/php"; 
53837 +       skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.4/sapi/cgi/php";
53838         $tf->{CONFIGFILE} = 'fastcgi-13.conf';
53839         ok($tf->start_proc == 0, "Starting lighttpd with $tf->{CONFIGFILE}") or die();
53840         $t->{REQUEST}  = ( <<EOF
53841 @@ -285,6 +285,34 @@
53842         $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'test123' } ];
53843         ok($tf->handle_http($t) == 0, 'line-ending \r\n + \r\n');
53844  
53845 +    # X-LIGHTTPD-send-file
53846 +       $t->{REQUEST}  = ( <<EOF
53847 +GET /index.fcgi?x-lighttpd-send-file HTTP/1.0
53848 +Host: www.example.org
53849 +EOF
53850 + );
53851 +       $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53852 +' } ];
53853 +       ok($tf->handle_http($t) == 0, 'X-LIGHTTPD-send-file');
53854 +    # X-Sendfile
53855 +       $t->{REQUEST}  = ( <<EOF
53856 +GET /index.fcgi?xsendfile HTTP/1.0
53857 +Host: www.example.org
53858 +EOF
53859 + );
53860 +       $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53861 +' } ];
53862 +       ok($tf->handle_http($t) == 0, 'X-Sendfile');
53863 +
53864 +       $t->{REQUEST}  = ( <<EOF
53865 +GET /index.fcgi?xsendfile-mixed-case HTTP/1.0
53866 +Host: www.example.org
53867 +EOF
53868 + );
53869 +       $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53870 +' } ];
53871 +       ok($tf->handle_http($t) == 0, 'X-SeNdFiLe in mixed case');
53872 +
53873         $t->{REQUEST}  = ( <<EOF
53874  GET /index.fcgi?die-at-end HTTP/1.0
53875  Host: www.example.org
53876 --- ../lighttpd-1.4.11/tests/mod-proxy.t        1970-01-01 03:00:00.000000000 +0300
53877 +++ lighttpd-1.4.12/tests/mod-proxy.t   2006-07-18 13:03:40.000000000 +0300
53878 @@ -0,0 +1,175 @@
53879 +#!/usr/bin/env perl
53880 +BEGIN {
53881 +    # add current source dir to the include-path
53882 +    # we need this for make distcheck
53883 +   (my $srcdir = $0) =~ s#/[^/]+$#/#;
53884 +   unshift @INC, $srcdir;
53885 +}
53886 +
53887 +use strict;
53888 +use IO::Socket;
53889 +use Test::More tests => 21;
53890 +use LightyTest;
53891 +
53892 +my $tf_proxy = LightyTest->new();
53893 +my $tf_backend1 = LightyTest->new();
53894 +my $tf_backend2 = LightyTest->new();
53895 +
53896 +my $t;
53897 +
53898 +## we need two procs
53899 +## 1. the real webserver
53900 +## 2. the proxy server
53901 +
53902 +SKIP: {
53903 +  skip "disabled for now", 21;
53904 +$tf_proxy->{PORT} = 2048;
53905 +$tf_proxy->{CONFIGFILE} = 'proxy.conf';
53906 +$tf_proxy->{LIGHTTPD_PIDFILE} = $tf_proxy->{SRCDIR}.'/tmp/lighttpd/lighttpd-proxy.pid';
53907 +
53908 +$tf_backend1->{PORT} = 2050;
53909 +$tf_backend1->{CONFIGFILE} = 'proxy-backend-1.conf';
53910 +$tf_backend1->{LIGHTTPD_PIDFILE} = $tf_backend1->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-1.pid';
53911 +
53912 +$tf_backend2->{PORT} = 2051;
53913 +$tf_backend2->{CONFIGFILE} = 'proxy-backend-2.conf';
53914 +$tf_backend2->{LIGHTTPD_PIDFILE} = $tf_backend2->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-2.pid';
53915 +
53916 +
53917 +ok($tf_backend1->start_proc == 0, "Starting lighttpd") or die();
53918 +
53919 +ok($tf_proxy->start_proc == 0, "Starting lighttpd as proxy") or die();
53920 +
53921 +sleep(1);
53922 +
53923 +$t->{REQUEST}  = ( <<EOF
53924 +GET /index.html HTTP/1.0
53925 +Host: www.example.org
53926 +EOF
53927 + );
53928 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53929 +ok($tf_proxy->handle_http($t) == 0, 'valid request');
53930 +
53931 +$t->{REQUEST}  = ( <<EOF
53932 +GET /index.html HTTP/1.0
53933 +Host: www.example.org
53934 +EOF
53935 + );
53936 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Server' => 'proxy-backend-1' } ];
53937 +ok($tf_proxy->handle_http($t) == 0, 'drop Server from real server');
53938 +
53939 +$t->{REQUEST}  = ( <<EOF
53940 +GET /balance-rr/foo HTTP/1.0
53941 +Host: www.example.org
53942 +EOF
53943 + );
53944 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53945 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one backend');
53946 +
53947 +$t->{REQUEST}  = ( <<EOF
53948 +GET /balance-rr/foo HTTP/1.0
53949 +Host: www.example.org
53950 +EOF
53951 + );
53952 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53953 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one host down, failover');
53954 +
53955 +$t->{REQUEST}  = ( <<EOF
53956 +GET /balance-fair/foo HTTP/1.0
53957 +Host: www.example.org
53958 +EOF
53959 + );
53960 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53961 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - one backend');
53962 +
53963 +## backend 2 starting 
53964 +ok($tf_backend2->start_proc == 0, "Starting second proxy backend") or die();
53965 +
53966 +$t->{REQUEST}  = ( <<EOF
53967 +GET /balance-rr/foo HTTP/1.0
53968 +Host: www.example.org
53969 +EOF
53970 + );
53971 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53972 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 1');
53973 +
53974 +$t->{REQUEST}  = ( <<EOF
53975 +GET /balance-rr/foo HTTP/1.0
53976 +Host: www.example.org
53977 +EOF
53978 + );
53979 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53980 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 2');
53981 +
53982 +$t->{REQUEST}  = ( <<EOF
53983 +GET /balance-hash/foo HTTP/1.0
53984 +Host: www.example.org
53985 +EOF
53986 + );
53987 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53988 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1');
53989 +
53990 +$t->{REQUEST}  = ( <<EOF
53991 +GET /balance-hash/foo HTTP/1.0
53992 +Host: www.example.org
53993 +EOF
53994 + );
53995 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53996 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1 - same URL');
53997 +
53998 +$t->{REQUEST}  = ( <<EOF
53999 +GET /balance-hash/bar HTTP/1.0
54000 +Host: www.example.org
54001 +EOF
54002 + );
54003 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54004 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2');
54005 +
54006 +$t->{REQUEST}  = ( <<EOF
54007 +GET /balance-hash/bar HTTP/1.0
54008 +Host: www.example.org
54009 +EOF
54010 + );
54011 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54012 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2 - same URL');
54013 +
54014 +## backend 1 stopping, failover 
54015 +ok($tf_backend1->stop_proc == 0, "Stopping backend 1");
54016 +
54017 +$t->{REQUEST}  = ( <<EOF
54018 +GET /balance-hash/foo HTTP/1.0
54019 +Host: www.example.org
54020 +EOF
54021 + );
54022 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54023 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2');
54024 +
54025 +$t->{REQUEST}  = ( <<EOF
54026 +GET /balance-hash/bar HTTP/1.0
54027 +Host: www.example.org
54028 +EOF
54029 + );
54030 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54031 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2 - same URL');
54032 +
54033 +$t->{REQUEST}  = ( <<EOF
54034 +GET /balance-rr/foo HTTP/1.0
54035 +Host: www.example.org
54036 +EOF
54037 + );
54038 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54039 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - failover to backend 2');
54040 +
54041 +$t->{REQUEST}  = ( <<EOF
54042 +GET /balance-fair/foo HTTP/1.0
54043 +Host: www.example.org
54044 +EOF
54045 + );
54046 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54047 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - failover to backend 2');
54048 +
54049 +
54050 +ok($tf_backend2->stop_proc == 0, "Stopping lighttpd");
54051 +
54052 +ok($tf_proxy->stop_proc == 0, "Stopping lighttpd proxy");
54053 +}
54054 --- ../lighttpd-1.4.11/tests/proxy-backend-1.conf       1970-01-01 03:00:00.000000000 +0300
54055 +++ lighttpd-1.4.12/tests/proxy-backend-1.conf  2006-07-16 00:26:05.000000000 +0300
54056 @@ -0,0 +1,7 @@
54057 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54058 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-1.pid"
54059 +
54060 +include "default.conf"
54061 +
54062 +
54063 +server.tag = "proxy-backend-1"
54064 --- ../lighttpd-1.4.11/tests/proxy-backend-2.conf       1970-01-01 03:00:00.000000000 +0300
54065 +++ lighttpd-1.4.12/tests/proxy-backend-2.conf  2006-07-16 00:26:04.000000000 +0300
54066 @@ -0,0 +1,7 @@
54067 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54068 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-2.pid"
54069 +
54070 +include "default.conf"
54071 +
54072 +
54073 +server.tag = "proxy-backend-2"
54074 --- ../lighttpd-1.4.11/tests/proxy.conf 1970-01-01 03:00:00.000000000 +0300
54075 +++ lighttpd-1.4.12/tests/proxy.conf    2006-07-16 00:26:05.000000000 +0300
54076 @@ -0,0 +1,26 @@
54077 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54078 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd-proxy.pid"
54079 +server.tag = "proxy"
54080 +
54081 +include "default.conf"
54082 +
54083 +## 127.0.0.1 and 127.0.0.2 are the same host
54084 +proxy.server              = ( 
54085 +  "" => (( "host" => "127.0.0.1",
54086 +          "port" => 2050 ),
54087 +         ( "host" => "127.0.0.2",
54088 +           "port" => 2051 )
54089 +  ))
54090 +               
54091 +$HTTP["url"] =~ "^/balance-rr/" {
54092 +  proxy.balance = "round-robin"
54093 +}
54094 +
54095 +$HTTP["url"] =~ "^/balance-hash/" {
54096 +  proxy.balance = "hash"
54097 +}
54098 +
54099 +$HTTP["url"] =~ "^/balance-fair/" {
54100 +  proxy.balance = "fair"
54101 +}
54102 +
54103 --- ../lighttpd-1.4.11/tests/var-include.conf   2005-08-27 17:44:19.000000000 +0300
54104 +++ lighttpd-1.4.12/tests/var-include.conf      2006-07-16 00:26:05.000000000 +0300
54105 @@ -2,15 +2,15 @@
54106  debug.log-request-handling = "enable"
54107  debug.log-condition-handling = "enable"
54108  
54109 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
54110 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
54111 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54112 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
54113  
54114  ## bind to port (default: 80)
54115  server.port                 = 2048
54116  
54117  ## bind to localhost (default: all interfaces)
54118  server.bind                = "localhost"
54119 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
54120 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
54121  server.name                = "www.example.org"
54122  server.tag                 = "Apache 1.3.29"
54123  
54124 @@ -21,19 +21,19 @@
54125  ######################## MODULE CONFIG ############################
54126  
54127  
54128 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
54129 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
54130  
54131  mimetype.assign             = ( ".html" => "text/html" )
54132  
54133  url.redirect = ("^" => "/default")
54134  
54135  $HTTP["host"] == "www.example.org" {
54136 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
54137 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54138    server.name = "www.example.org"
54139    url.redirect = ("^" => "/redirect")
54140  }
54141  $HTTP["host"] == "test.example.org" {
54142 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
54143 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54144    server.name = "test.example.org"
54145    var.myvar = "good"
54146    var.one = 1
This page took 4.591914 seconds and 3 git commands to generate.